shithub: hugo

Download patch

ref: 930a3df1b79d21f005a63918b89cc01ae5a4cd9e
parent: e49a2b83ad9825a978ecbf0ff5fd9b7331690c17
author: Bjørn Erik Pedersen <[email protected]>
date: Sun Mar 26 15:34:30 EDT 2017

hugolib, output: Restrict Render to regular Pages

Using it for list pages doesn't work and has potential weird side-effects.

The user probably meant to range over .Site.ReqularPages, and that is now marked clearly in the log.

--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -1721,3 +1721,11 @@
 		p.URLPath.URL = "/" + path.Join(p.sections...) + "/"
 	}
 }
+
+// Used in error logs.
+func (p *Page) pathOrTitle() string {
+	if p.Path() != "" {
+		return p.Path()
+	}
+	return p.Title
+}
--- a/hugolib/page_output.go
+++ b/hugolib/page_output.go
@@ -21,6 +21,7 @@
 
 	"github.com/spf13/hugo/media"
 
+	"github.com/spf13/hugo/helpers"
 	"github.com/spf13/hugo/output"
 )
 
@@ -85,9 +86,9 @@
 	return c
 }
 
-func (p *PageOutput) layouts(layouts ...string) []string {
+func (p *PageOutput) layouts(layouts ...string) ([]string, error) {
 	if len(layouts) == 0 && p.selfLayout != "" {
-		return []string{p.selfLayout}
+		return []string{p.selfLayout}, nil
 	}
 
 	layoutOverride := ""
@@ -106,7 +107,11 @@
 		return template.HTML("")
 	}
 
-	l := p.layouts(layout...)
+	l, err := p.layouts(layout...)
+	if err != nil {
+		helpers.DistinctErrorLog.Printf("in .Render: Failed to resolve layout %q for page %q", layout, p.pathOrTitle())
+		return template.HTML("")
+	}
 	return p.s.Tmpl.ExecuteTemplateToHTML(p, l...)
 }
 
@@ -122,7 +127,7 @@
 		pageOutput, err := newPageOutput(p, true, outFormat)
 
 		if err != nil {
-			p.s.Log.ERROR.Printf("Failed to create output page for type %q for page %q: %s", outFormat.Name, p, err)
+			p.s.Log.ERROR.Printf("Failed to create output page for type %q for page %q: %s", outFormat.Name, p.pathOrTitle(), err)
 			return
 		}
 
@@ -137,7 +142,7 @@
 // for list pages.
 func (p *Page) checkRender() bool {
 	if p.Kind != KindPage {
-		p.s.Log.ERROR.Printf(".Render only available for regular pages, not for %q of kind %q", p.Path(), p.Kind)
+		helpers.DistinctErrorLog.Printf(".Render only available for regular pages, not for of kind %q. You probably meant .Site.RegularPages and not.Site.Pages.", p.Kind)
 		return false
 	}
 	return true
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -1668,7 +1668,7 @@
 	return KindSection
 }
 
-func (s *Site) layouts(p *PageOutput) []string {
+func (s *Site) layouts(p *PageOutput) ([]string, error) {
 	return s.layoutHandler.For(p.layoutDescriptor, "", p.outputFormat)
 }
 
--- a/hugolib/site_render.go
+++ b/hugolib/site_render.go
@@ -91,7 +91,11 @@
 			if page.selfLayout != "" {
 				layouts = []string{page.selfLayout}
 			} else {
-				layouts = s.layouts(pageOutput)
+				layouts, err = s.layouts(pageOutput)
+				if err != nil {
+					s.Log.ERROR.Printf("Failed to resolve layout output %q for page %q: %s", outFormat.Name, page, err)
+					continue
+				}
 			}
 
 			switch pageOutput.outputFormat.Name {
@@ -161,8 +165,12 @@
 			pageNumber := i + 1
 			addend := fmt.Sprintf("/%s/%d", paginatePath, pageNumber)
 			targetPath, _ := p.targetPath(addend)
-			layouts := p.layouts()
+			layouts, err := p.layouts()
 
+			if err != nil {
+				return err
+			}
+
 			if err := s.renderAndWritePage(
 				pagerNode.Title,
 				targetPath, pagerNode, layouts...); err != nil {
@@ -200,10 +208,13 @@
 		p.Data["Pages"] = p.Pages
 	}
 
-	layouts := s.layoutHandler.For(
+	layouts, err := s.layoutHandler.For(
 		p.layoutDescriptor,
 		"",
 		p.outputFormat)
+	if err != nil {
+		return err
+	}
 
 	// TODO(bep) output deprecate/handle rssURI
 	targetPath, err := p.targetPath()
--- a/output/layout.go
+++ b/output/layout.go
@@ -83,7 +83,7 @@
 `
 )
 
-func (l *LayoutHandler) For(d LayoutDescriptor, layoutOverride string, f Format) []string {
+func (l *LayoutHandler) For(d LayoutDescriptor, layoutOverride string, f Format) ([]string, error) {
 
 	// We will get lots of requests for the same layouts, so avoid recalculations.
 	key := layoutCacheKey{d, layoutOverride, f}
@@ -90,12 +90,16 @@
 	l.mu.RLock()
 	if cacheVal, found := l.cache[key]; found {
 		l.mu.RUnlock()
-		return cacheVal
+		return cacheVal, nil
 	}
 	l.mu.RUnlock()
 
 	var layouts []string
 
+	if layoutOverride != "" && d.Kind != "page" {
+		return layouts, fmt.Errorf("Custom layout (%q) only supported for regular pages, not kind %q", layoutOverride, d.Kind)
+	}
+
 	layout := d.Layout
 
 	if layoutOverride != "" {
@@ -106,7 +110,7 @@
 
 	if d.Kind == "page" {
 		if isRSS {
-			return []string{}
+			return []string{}, nil
 		}
 		layouts = regularPageLayouts(d.Type, layout, f)
 	} else {
@@ -148,7 +152,7 @@
 			}
 		}
 
-		return layoutsWithThemeLayouts
+		return layoutsWithThemeLayouts, nil
 	}
 
 	l.mu.Lock()
@@ -155,7 +159,7 @@
 	l.cache[key] = layouts
 	l.mu.Unlock()
 
-	return layouts
+	return layouts, nil
 }
 
 func resolveListTemplate(d LayoutDescriptor, f Format,
--- a/output/layout_test.go
+++ b/output/layout_test.go
@@ -68,8 +68,9 @@
 		t.Run(this.name, func(t *testing.T) {
 			l := NewLayoutHandler(this.hasTheme)
 
-			layouts := l.For(this.d, this.layoutOverride, this.tp)
+			layouts, err := l.For(this.d, this.layoutOverride, this.tp)
 
+			require.NoError(t, err)
 			require.NotNil(t, layouts)
 			require.True(t, len(layouts) >= len(this.expect))
 			// Not checking the complete list for now ...
@@ -83,6 +84,10 @@
 		})
 	}
 
+	l := NewLayoutHandler(false)
+	_, err := l.For(LayoutDescriptor{Kind: "taxonomyTerm", Section: "tag"}, "override", RSSFormat)
+	require.Error(t, err)
+
 }
 
 func BenchmarkLayout(b *testing.B) {
@@ -90,7 +95,8 @@
 	l := NewLayoutHandler(false)
 
 	for i := 0; i < b.N; i++ {
-		layouts := l.For(descriptor, "", HTMLFormat)
+		layouts, err := l.For(descriptor, "", HTMLFormat)
+		require.NoError(b, err)
 		require.NotEmpty(b, layouts)
 	}
 }