shithub: hugo

Download patch

ref: e371ac0b6f56bdffe92b9e74dae571a003123912
parent: e7d0bc8a7433e39dc22fe5096a0eb663c16c0d6a
author: Bjørn Erik Pedersen <[email protected]>
date: Sun Oct 30 13:59:24 EDT 2016

node to page: Basic outline

Updates #2297

--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -31,6 +31,15 @@
 	jww "github.com/spf13/jwalterweatherman"
 )
 
+// Temporary feature flag to ease the refactoring of node vs page, see
+// https://github.com/spf13/hugo/issues/2297
+// TODO(bep) eventually remove
+var nodePageFeatureFlag bool
+
+func toggleNodePageFeatureFlag() {
+	nodePageFeatureFlag = !nodePageFeatureFlag
+}
+
 // HugoSites represents the sites to build. Each site represents a language.
 type HugoSites struct {
 	Sites []*Site
@@ -561,6 +570,16 @@
 	if page.IsExpired() {
 		s.expiredCount++
 	}
+}
+
+func (h *HugoSites) findPagesByNodeType(n NodeType) Pages {
+	var pages Pages
+	for _, p := range h.Sites[0].AllPages {
+		if p.NodeType == n {
+			pages = append(pages, p)
+		}
+	}
+	return pages
 }
 
 // Convenience func used in tests to build a single site/language excluding render phase.
--- a/hugolib/node.go
+++ b/hugolib/node.go
@@ -26,7 +26,23 @@
 	"github.com/spf13/hugo/helpers"
 )
 
+// TODO(bep) np add String()
+type NodeType int
+
+const (
+	NodePage NodeType = iota
+
+	// The rest are node types; home page, sections etc.
+	NodeHome
+)
+
+func (p NodeType) IsNode() bool {
+	return p >= NodeHome
+}
+
 type Node struct {
+	NodeType NodeType
+
 	// a natural key that should be unique for this site
 	// for the home page this will typically be "home", but it can anything
 	// as long as it is the same for repeated builds.
@@ -44,7 +60,6 @@
 	Lastmod     time.Time
 	Sitemap     Sitemap
 	URLPath
-	IsHome        bool
 	paginator     *Pager
 	paginatorInit sync.Once
 	scratch       *Scratch
@@ -151,11 +166,15 @@
 }
 
 func (n *Node) IsNode() bool {
-	return true
+	return n.NodeType.IsNode()
 }
 
+func (n *Node) IsHome() bool {
+	return n.NodeType == NodeHome
+}
+
 func (n *Node) IsPage() bool {
-	return !n.IsNode()
+	return n.NodeType == NodePage
 }
 
 func (n *Node) Ref(ref string) (string, error) {
@@ -315,4 +334,12 @@
 		return outfile
 	}
 	return helpers.FilePathSeparator + filepath.Join(n.Lang(), outfile)
+}
+
+func nodeTypeFromFilename(filename string) NodeType {
+	// TODO(bep) np
+	if !strings.HasPrefix(filename, "_node") {
+		return NodePage
+	}
+	return NodeHome
 }
--- /dev/null
+++ b/hugolib/node_as_page_test.go
@@ -1,0 +1,103 @@
+// Copyright 2016 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+	"fmt"
+	"path/filepath"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+/*
+	This file will test the "making everything a page" transition.
+
+	See https://github.com/spf13/hugo/issues/2297
+
+*/
+
+func TestHomeAsPage(t *testing.T) {
+	nodePageFeatureFlag = true
+	defer toggleNodePageFeatureFlag()
+
+	/* Will have to decide what to name the node content files, but:
+
+		Home page should have:
+		Content, shortcode support
+	   	Metadata (title, dates etc.)
+		Params
+	   	Taxonomies (categories, tags)
+
+	*/
+
+	testCommonResetState()
+
+	writeSource(t, filepath.Join("content", "_node.md"), `---
+title: Home Sweet Home!
+---
+Home **Content!**
+`)
+
+	writeSource(t, filepath.Join("layouts", "index.html"), `
+Index Title: {{ .Title }}
+Index Content: {{ .Content }}
+# Pages: {{ len .Data.Pages }}
+`)
+
+	writeSource(t, filepath.Join("layouts", "_default", "single.html"), `
+Single Title: {{ .Title }}
+Single Content: {{ .Content }}
+`)
+
+	// Add some regular pages
+	for i := 0; i < 10; i++ {
+		writeSource(t, filepath.Join("content", fmt.Sprintf("regular%d.md", i)), fmt.Sprintf(`---
+title: Page %d
+---
+Content Page %d
+`, i, i))
+	}
+
+	s := newSiteDefaultLang()
+
+	if err := buildAndRenderSite(s); err != nil {
+		t.Fatalf("Failed to build site: %s", err)
+	}
+
+	assertFileContent(t, filepath.Join("public", "index.html"), false,
+		"Index Title: Home Sweet Home!",
+		"Home <strong>Content!</strong>",
+		"# Pages: 10")
+	assertFileContent(t, filepath.Join("public", "regular1", "index.html"), false, "Single Title: Page 1", "Content Page 1")
+
+	h := s.owner
+	nodes := h.findPagesByNodeType(NodeHome)
+	require.Len(t, nodes, 1)
+
+	home := nodes[0]
+
+	require.True(t, home.IsHome())
+	require.True(t, home.IsNode())
+	require.False(t, home.IsPage())
+
+	pages := h.findPagesByNodeType(NodePage)
+	require.Len(t, pages, 10)
+
+	first := pages[0]
+	require.False(t, first.IsHome())
+	require.False(t, first.IsNode())
+	require.True(t, first.IsPage())
+
+}
--- a/hugolib/node_test.go
+++ b/hugolib/node_test.go
@@ -30,7 +30,7 @@
 		{func(n *Node) bool { return n.Now().Unix() == time.Now().Unix() }},
 	} {
 
-		n := &Node{}
+		n := &Node{NodeType: NodeHome}
 		n.RSSLink = "rssLink"
 
 		if !this.assertFunc(n) {
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -182,14 +182,6 @@
 	})
 }
 
-func (p *Page) IsNode() bool {
-	return false
-}
-
-func (p *Page) IsPage() bool {
-	return true
-}
-
 // Param is a convenience method to do lookups in Page's and Site's Params map,
 // in that order.
 //
@@ -423,7 +415,7 @@
 func newPage(filename string) *Page {
 	page := Page{contentType: "",
 		Source:       Source{File: *source.NewFile(filename)},
-		Node:         Node{Keywords: []string{}, Sitemap: Sitemap{Priority: -1}},
+		Node:         Node{NodeType: nodeTypeFromFilename(filename), Keywords: []string{}, Sitemap: Sitemap{Priority: -1}},
 		Params:       make(map[string]interface{}),
 		translations: make(Pages, 0),
 	}
@@ -457,6 +449,11 @@
 		return p.layoutsCalculated
 	}
 
+	// TODO(bep) np
+	if p.NodeType == NodeHome {
+		return []string{"index.html", "_default/list.html"}
+	}
+
 	if p.Layout != "" {
 		return layouts(p.Type(), p.Layout)
 	}
@@ -1136,6 +1133,10 @@
 }
 
 func (p *Page) TargetPath() (outfile string) {
+	// TODO(bep) ml
+	if p.NodeType == NodeHome {
+		return "index.html"
+	}
 	// Always use URL if it's specified
 	if len(strings.TrimSpace(p.URLPath.URL)) > 2 {
 		outfile = strings.TrimSpace(p.URLPath.URL)
--- a/hugolib/page_test.go
+++ b/hugolib/page_test.go
@@ -645,7 +645,7 @@
 
 		// issue #2290: Path is relative to the content dir and will continue to be so.
 		require.Equal(t, filepath.FromSlash(fmt.Sprintf("p0.%s", ext)), p.Path())
-		assert.False(t, p.IsHome)
+		assert.False(t, p.IsHome())
 		checkPageTitle(t, p, "Simple")
 		checkPageContent(t, p, normalizeExpected(ext, "<p>Simple Page</p>\n"))
 		checkPageSummary(t, p, "Simple Page")
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -1678,6 +1678,8 @@
 func pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.WaitGroup) {
 	defer wg.Done()
 	for p := range pages {
+		// TODO(bep) np paginator
+		s.preparePage(p)
 		err := s.renderAndWritePage("page "+p.FullFilePath(), p.TargetPath(), p, s.appendThemeTemplates(p.layouts())...)
 		if err != nil {
 			results <- err
@@ -1685,6 +1687,17 @@
 	}
 }
 
+func (s *Site) preparePage(p *Page) {
+	// TODO(bep) np the order of it all
+	switch p.NodeType {
+	case NodePage:
+	case NodeHome:
+		p.Data = make(map[string]interface{})
+		// TODO(bep) np cache the below
+		p.Data["Pages"] = s.owner.findPagesByNodeType(NodePage)
+	}
+}
+
 func errorCollator(results <-chan error, errs chan<- error) {
 	errMsgs := []string{}
 	for err := range results {
@@ -2028,6 +2041,11 @@
 }
 
 func (s *Site) renderHomePage(prepare bool) error {
+	// TODO(bep) np remove this and related
+	if nodePageFeatureFlag {
+		return nil
+	}
+
 	n := s.newHomeNode(prepare, 0)
 	if prepare {
 		return nil
@@ -2118,7 +2136,7 @@
 func (s *Site) newHomeNode(prepare bool, counter int) *Node {
 	n := s.nodeLookup("home", counter, prepare)
 	n.Title = n.Site.Title
-	n.IsHome = true
+	n.NodeType = NodeHome
 	s.setURLs(n, "/")
 	n.Data["Pages"] = s.Pages
 	if len(s.Pages) != 0 {
@@ -2373,7 +2391,7 @@
 	}
 
 	// For performance reasons we only inject the Hugo generator tag on the home page.
-	if n, ok := d.(*Node); ok && n.IsHome {
+	if n, ok := d.(*Node); ok && n.IsHome() {
 		if !viper.GetBool("disableHugoGeneratorInject") {
 			transformLinks = append(transformLinks, transform.HugoGeneratorInject)
 		}
--- a/hugolib/site_test.go
+++ b/hugolib/site_test.go
@@ -378,7 +378,7 @@
 	}
 
 	for _, p := range s.Pages {
-		assert.False(t, p.IsHome)
+		assert.False(t, p.IsHome())
 	}
 
 	for _, test := range tests {