diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index 2ae58854b..5f0168d7a 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -31,6 +31,15 @@ import ( 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 @@ -563,6 +572,16 @@ func (s *Site) updateBuildStats(page *Page) { } } +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. func buildSiteSkipRender(s *Site, additionalTemplates ...string) error { return doBuildSite(s, false, additionalTemplates...) diff --git a/hugolib/node.go b/hugolib/node.go index 16c83e2e8..a3d9ca699 100644 --- a/hugolib/node.go +++ b/hugolib/node.go @@ -26,7 +26,23 @@ import ( "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 @@ type Node struct { Lastmod time.Time Sitemap Sitemap URLPath - IsHome bool paginator *Pager paginatorInit sync.Once scratch *Scratch @@ -151,11 +166,15 @@ func (n *Node) RSSlink() template.HTML { } 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) { @@ -316,3 +335,11 @@ func (n *Node) addLangFilepathPrefix(outfile string) string { } 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 +} diff --git a/hugolib/node_as_page_test.go b/hugolib/node_as_page_test.go new file mode 100644 index 000000000..0bbc99fd8 --- /dev/null +++ b/hugolib/node_as_page_test.go @@ -0,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 Content!", + "# 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()) + +} diff --git a/hugolib/node_test.go b/hugolib/node_test.go index 3b8f868dc..98c97cae6 100644 --- a/hugolib/node_test.go +++ b/hugolib/node_test.go @@ -30,7 +30,7 @@ func TestNodeSimpleMethods(t *testing.T) { {func(n *Node) bool { return n.Now().Unix() == time.Now().Unix() }}, } { - n := &Node{} + n := &Node{NodeType: NodeHome} n.RSSLink = "rssLink" if !this.assertFunc(n) { diff --git a/hugolib/page.go b/hugolib/page.go index de7391599..4c4b0d29e 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -182,14 +182,6 @@ func (p *Page) initPlainWords() { }) } -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 (p *Page) getRenderingConfig() *helpers.Blackfriday { 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 @@ func (p *Page) layouts(l ...string) []string { 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) FullFilePath() string { } 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) diff --git a/hugolib/page_test.go b/hugolib/page_test.go index 386ea8309..86baf44f2 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -645,7 +645,7 @@ func TestCreateNewPage(t *testing.T) { // 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, "

Simple Page

\n")) checkPageSummary(t, p, "Simple Page") diff --git a/hugolib/site.go b/hugolib/site.go index fa5f9f2cf..55749aeb5 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -1678,6 +1678,8 @@ func (s *Site) renderPages() error { 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 pageRenderer(s *Site, pages <-chan *Page, results chan<- error, wg *sync.Wa } } +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) renderSectionLists(prepare bool) error { } 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) renderHomePage(prepare bool) error { 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 @@ func (s *Site) renderAndWritePage(name string, dest string, d interface{}, layou } // 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) } diff --git a/hugolib/site_test.go b/hugolib/site_test.go index f368a959f..b71548c46 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -378,7 +378,7 @@ func doTestShouldAlwaysHaveUglyURLs(t *testing.T, uglyURLs bool) { } for _, p := range s.Pages { - assert.False(t, p.IsHome) + assert.False(t, p.IsHome()) } for _, test := range tests {