From c8d3124ddeb86093caf1b18dfaa328c3053e5b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sun, 13 Nov 2016 14:27:10 +0100 Subject: [PATCH] node to page: Remove Node And misc. TODO-fixes Updates #2297 --- hugolib/embedded_shortcodes_test.go | 4 +- hugolib/gitinfo.go | 5 +- hugolib/hugo_sites.go | 35 +-- hugolib/hugo_sites_build.go | 8 +- hugolib/hugo_sites_build_test.go | 58 ++-- hugolib/menu.go | 2 - hugolib/menu_test.go | 66 +++-- hugolib/node.go | 334 ---------------------- hugolib/node_as_page_test.go | 6 +- hugolib/page.go | 429 ++++++++++++++++++++++++---- hugolib/pageSort_test.go | 11 +- hugolib/page_collections.go | 5 +- hugolib/page_permalink_test.go | 10 +- hugolib/page_test.go | 30 +- hugolib/pagination.go | 28 +- hugolib/pagination_test.go | 10 +- hugolib/shortcode_test.go | 4 +- hugolib/site.go | 4 + hugolib/siteJSONEncode_test.go | 2 +- hugolib/site_render.go | 3 +- hugolib/site_test.go | 42 +-- hugolib/taxonomy.go | 9 + 22 files changed, 538 insertions(+), 567 deletions(-) delete mode 100644 hugolib/node.go diff --git a/hugolib/embedded_shortcodes_test.go b/hugolib/embedded_shortcodes_test.go index 160e36fd5..f61ed2383 100644 --- a/hugolib/embedded_shortcodes_test.go +++ b/hugolib/embedded_shortcodes_test.go @@ -66,9 +66,9 @@ func doTestShortcodeCrossrefs(t *testing.T, relative bool) { require.NoError(t, err) require.NoError(t, sites.Build(BuildCfg{})) - require.Len(t, sites.Sites[0].regularPages, 1) + require.Len(t, sites.Sites[0].RegularPages, 1) - output := string(sites.Sites[0].regularPages[0].Content) + output := string(sites.Sites[0].RegularPages[0].Content) if !strings.Contains(output, expected) { t.Errorf("Got\n%q\nExpected\n%q", output, expected) diff --git a/hugolib/gitinfo.go b/hugolib/gitinfo.go index 520b7e5d0..b2119048e 100644 --- a/hugolib/gitinfo.go +++ b/hugolib/gitinfo.go @@ -52,7 +52,10 @@ func (h *HugoSites) assembleGitInfo() { s := h.Sites[0] for _, p := range s.AllPages { - // TODO(bep) np consider other nodes + if p.Path() == "" { + // Home page etc. with no content file. + continue + } // Git normalizes file paths on this form: filename := path.Join(contentRoot, contentDir, filepath.ToSlash(p.Path())) g, ok := gitMap[filename] diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index 78137f6c1..674a0645a 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -211,8 +211,6 @@ func (h *HugoSites) assignMissingTranslations() error { // createMissingPages creates home page, taxonomies etc. that isnt't created as an // effect of having a content file. func (h *HugoSites) createMissingPages() error { - // TODO(bep) np check node title etc. - var newPages Pages for _, s := range h.Sites { @@ -306,12 +304,11 @@ func (h *HugoSites) createMissingPages() error { // Move the new* methods after cleanup in site.go func (s *Site) newNodePage(typ string) *Page { return &Page{ - Kind: typ, - Node: Node{ - Data: make(map[string]interface{}), - Site: &s.Info, - language: s.Language, - }, site: s} + Kind: typ, + Data: make(map[string]interface{}), + Site: &s.Info, + language: s.Language, + site: s} } func (s *Site) newHomePage() *Page { @@ -321,8 +318,6 @@ func (s *Site) newHomePage() *Page { p.Data["Pages"] = pages p.Pages = pages s.setPageURLs(p, "/") - // TODO(bep) np check Data pages - // TODO(bep) np check setURLs return p } @@ -426,23 +421,7 @@ func (h *HugoSites) setupTranslations() { } } -// preRender performs build tasks that need to be done as late as possible. -// Shortcode handling is the main task in here. -// TODO(bep) We need to look at the whole handler-chain construct with he below in mind. -// TODO(bep) np clean -func (h *HugoSites) preRender(cfg BuildCfg, changed whatChanged) error { - - for _, s := range h.Sites { - if err := s.setCurrentLanguageConfig(); err != nil { - return err - } - s.preparePagesForRender(cfg, changed) - } - - return nil -} - -func (s *Site) preparePagesForRender(cfg BuildCfg, changed whatChanged) { +func (s *Site) preparePagesForRender(cfg *BuildCfg) { pageChan := make(chan *Page) wg := &sync.WaitGroup{} @@ -452,7 +431,7 @@ func (s *Site) preparePagesForRender(cfg BuildCfg, changed whatChanged) { defer wg.Done() for p := range pages { - if !changed.other && p.rendered { + if !cfg.whatChanged.other && p.rendered { // No need to process it again. continue } diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go index 32185dd4f..4f9ad4e04 100644 --- a/hugolib/hugo_sites_build.go +++ b/hugolib/hugo_sites_build.go @@ -169,11 +169,15 @@ func (h *HugoSites) assemble(config *BuildCfg) error { return err } - if err := h.preRender(*config, whatChanged{source: true, other: true}); err != nil { - return err + for _, s := range h.Sites { + if err := s.setCurrentLanguageConfig(); err != nil { + return err + } + s.preparePagesForRender(config) } return nil + } func (h *HugoSites) render(config *BuildCfg) error { diff --git a/hugolib/hugo_sites_build_test.go b/hugolib/hugo_sites_build_test.go index 7ef59bc26..3498de67f 100644 --- a/hugolib/hugo_sites_build_test.go +++ b/hugolib/hugo_sites_build_test.go @@ -83,8 +83,8 @@ func doTestMultiSitesMainLangInRoot(t *testing.T, defaultInSubDir bool) { require.Equal(t, "/blog/en/foo", enSite.Info.pathSpec.RelURL("foo", true)) - doc1en := enSite.regularPages[0] - doc1fr := frSite.regularPages[0] + doc1en := enSite.RegularPages[0] + doc1fr := frSite.RegularPages[0] enPerm, _ := doc1en.Permalink() enRelPerm, _ := doc1en.RelPermalink() @@ -216,24 +216,24 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) { assert.Equal(t, "en", enSite.Language.Lang) - if len(enSite.regularPages) != 4 { + if len(enSite.RegularPages) != 4 { t.Fatal("Expected 4 english pages") } assert.Len(t, enSite.Source.Files(), 14, "should have 13 source files") assert.Len(t, enSite.AllPages, 28, "should have 28 total pages (including translations and index types)") - doc1en := enSite.regularPages[0] + doc1en := enSite.RegularPages[0] permalink, err := doc1en.Permalink() assert.NoError(t, err, "permalink call failed") assert.Equal(t, "http://example.com/blog/en/sect/doc1-slug/", permalink, "invalid doc1.en permalink") assert.Len(t, doc1en.Translations(), 1, "doc1-en should have one translation, excluding itself") - doc2 := enSite.regularPages[1] + doc2 := enSite.RegularPages[1] permalink, err = doc2.Permalink() assert.NoError(t, err, "permalink call failed") assert.Equal(t, "http://example.com/blog/en/sect/doc2/", permalink, "invalid doc2 permalink") - doc3 := enSite.regularPages[2] + doc3 := enSite.RegularPages[2] permalink, err = doc3.Permalink() assert.NoError(t, err, "permalink call failed") // Note that /superbob is a custom URL set in frontmatter. @@ -276,10 +276,10 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) { frSite := sites.Sites[1] assert.Equal(t, "fr", frSite.Language.Lang) - assert.Len(t, frSite.regularPages, 3, "should have 3 pages") + assert.Len(t, frSite.RegularPages, 3, "should have 3 pages") assert.Len(t, frSite.AllPages, 28, "should have 28 total pages (including translations and nodes)") - for _, frenchPage := range frSite.regularPages { + for _, frenchPage := range frSite.RegularPages { assert.Equal(t, "fr", frenchPage.Lang()) } @@ -386,8 +386,8 @@ func TestMultiSitesRebuild(t *testing.T) { enSite := sites.Sites[0] frSite := sites.Sites[1] - require.Len(t, enSite.regularPages, 4) - require.Len(t, frSite.regularPages, 3) + require.Len(t, enSite.RegularPages, 4) + require.Len(t, frSite.RegularPages, 3) // Verify translations assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Hello") @@ -413,7 +413,7 @@ func TestMultiSitesRebuild(t *testing.T) { nil, []fsnotify.Event{{Name: "content/sect/doc2.en.md", Op: fsnotify.Remove}}, func(t *testing.T) { - require.Len(t, enSite.regularPages, 3, "1 en removed") + require.Len(t, enSite.RegularPages, 3, "1 en removed") // Check build stats require.Equal(t, 1, enSite.draftCount, "Draft") @@ -436,12 +436,12 @@ func TestMultiSitesRebuild(t *testing.T) { {Name: "content/new1.fr.md", Op: fsnotify.Create}, }, func(t *testing.T) { - require.Len(t, enSite.regularPages, 5) + require.Len(t, enSite.RegularPages, 5) require.Len(t, enSite.AllPages, 30) - require.Len(t, frSite.regularPages, 4) - require.Equal(t, "new_fr_1", frSite.regularPages[3].Title) - require.Equal(t, "new_en_2", enSite.regularPages[0].Title) - require.Equal(t, "new_en_1", enSite.regularPages[1].Title) + require.Len(t, frSite.RegularPages, 4) + require.Equal(t, "new_fr_1", frSite.RegularPages[3].Title) + require.Equal(t, "new_en_2", enSite.RegularPages[0].Title) + require.Equal(t, "new_en_1", enSite.RegularPages[1].Title) rendered := readDestination(t, "public/en/new1/index.html") require.True(t, strings.Contains(rendered, "new_en_1"), rendered) @@ -456,7 +456,7 @@ func TestMultiSitesRebuild(t *testing.T) { }, []fsnotify.Event{{Name: "content/sect/doc1.en.md", Op: fsnotify.Write}}, func(t *testing.T) { - require.Len(t, enSite.regularPages, 5) + require.Len(t, enSite.RegularPages, 5) doc1 := readDestination(t, "public/en/sect/doc1-slug/index.html") require.True(t, strings.Contains(doc1, "CHANGED"), doc1) @@ -474,8 +474,8 @@ func TestMultiSitesRebuild(t *testing.T) { {Name: "content/new1.en.md", Op: fsnotify.Rename}, }, func(t *testing.T) { - require.Len(t, enSite.regularPages, 5, "Rename") - require.Equal(t, "new_en_1", enSite.regularPages[1].Title) + require.Len(t, enSite.RegularPages, 5, "Rename") + require.Equal(t, "new_en_1", enSite.RegularPages[1].Title) rendered := readDestination(t, "public/en/new1renamed/index.html") require.True(t, strings.Contains(rendered, "new_en_1"), rendered) }}, @@ -489,9 +489,9 @@ func TestMultiSitesRebuild(t *testing.T) { }, []fsnotify.Event{{Name: "layouts/_default/single.html", Op: fsnotify.Write}}, func(t *testing.T) { - require.Len(t, enSite.regularPages, 5) + require.Len(t, enSite.RegularPages, 5) require.Len(t, enSite.AllPages, 30) - require.Len(t, frSite.regularPages, 4) + require.Len(t, frSite.RegularPages, 4) doc1 := readDestination(t, "public/en/sect/doc1-slug/index.html") require.True(t, strings.Contains(doc1, "Template Changed"), doc1) }, @@ -506,9 +506,9 @@ func TestMultiSitesRebuild(t *testing.T) { }, []fsnotify.Event{{Name: "i18n/fr.yaml", Op: fsnotify.Write}}, func(t *testing.T) { - require.Len(t, enSite.regularPages, 5) + require.Len(t, enSite.RegularPages, 5) require.Len(t, enSite.AllPages, 30) - require.Len(t, frSite.regularPages, 4) + require.Len(t, frSite.RegularPages, 4) docEn := readDestination(t, "public/en/sect/doc1-slug/index.html") require.True(t, strings.Contains(docEn, "Hello"), "No Hello") docFr := readDestination(t, "public/fr/sect/doc1/index.html") @@ -530,9 +530,9 @@ func TestMultiSitesRebuild(t *testing.T) { {Name: "layouts/shortcodes/shortcode.html", Op: fsnotify.Write}, }, func(t *testing.T) { - require.Len(t, enSite.regularPages, 5) + require.Len(t, enSite.RegularPages, 5) require.Len(t, enSite.AllPages, 30) - require.Len(t, frSite.regularPages, 4) + require.Len(t, frSite.RegularPages, 4) assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Modified Shortcode: Salut") assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Single", "Modified Shortcode: Hello") }, @@ -626,12 +626,12 @@ title = "Svenska" require.Len(t, homeEn.Translations(), 4) require.Equal(t, "sv", homeEn.Translations()[0].Lang()) - require.Len(t, enSite.regularPages, 4) - require.Len(t, frSite.regularPages, 3) + require.Len(t, enSite.RegularPages, 4) + require.Len(t, frSite.RegularPages, 3) // Veriy Swedish site - require.Len(t, svSite.regularPages, 1) - svPage := svSite.regularPages[0] + require.Len(t, svSite.RegularPages, 1) + svPage := svSite.RegularPages[0] require.Equal(t, "Swedish Contentfile", svPage.Title) require.Equal(t, "sv", svPage.Lang()) require.Len(t, svPage.Translations(), 2) diff --git a/hugolib/menu.go b/hugolib/menu.go index 35991b1c7..116545a9a 100644 --- a/hugolib/menu.go +++ b/hugolib/menu.go @@ -21,8 +21,6 @@ import ( "github.com/spf13/cast" ) -// TODO(bep) np menu entries in section content etc.? - // MenuEntry represents a menu item defined in either Page front matter // or in the site config. type MenuEntry struct { diff --git a/hugolib/menu_test.go b/hugolib/menu_test.go index 447273f0b..460440fa8 100644 --- a/hugolib/menu_test.go +++ b/hugolib/menu_test.go @@ -208,7 +208,7 @@ func doTestPageMenuWithIdentifier(t *testing.T, menuPageSources []source.ByteSou s := setupMenuTests(t, menuPageSources) - assert.Equal(t, 3, len(s.regularPages), "Not enough pages") + assert.Equal(t, 3, len(s.RegularPages), "Not enough pages") me1 := findTestMenuEntryByID(s, "m1", "i1") me2 := findTestMenuEntryByID(s, "m1", "i2") @@ -246,7 +246,7 @@ func doTestPageMenuWithDuplicateName(t *testing.T, menuPageSources []source.Byte s := setupMenuTests(t, menuPageSources) - assert.Equal(t, 3, len(s.regularPages), "Not enough pages") + assert.Equal(t, 3, len(s.RegularPages), "Not enough pages") me1 := findTestMenuEntryByName(s, "m1", "n1") me2 := findTestMenuEntryByName(s, "m1", "n2") @@ -264,13 +264,13 @@ func TestPageMenu(t *testing.T) { s := setupMenuTests(t, menuPageSources) - if len(s.regularPages) != 3 { - t.Fatalf("Posts not created, expected 3 got %d", len(s.regularPages)) + if len(s.RegularPages) != 3 { + t.Fatalf("Posts not created, expected 3 got %d", len(s.RegularPages)) } - first := s.regularPages[0] - second := s.regularPages[1] - third := s.regularPages[2] + first := s.RegularPages[0] + second := s.RegularPages[1] + third := s.RegularPages[2] pOne := findTestMenuEntryByName(s, "p_one", "One") pTwo := findTestMenuEntryByID(s, "p_two", "Two") @@ -290,6 +290,10 @@ func TestPageMenu(t *testing.T) { {"p_one", third, pTwo, false, false}, } { + if i != 4 { + continue + } + isMenuCurrent := this.page.IsMenuCurrent(this.menu, this.menuItem) hasMenuCurrent := this.page.HasMenuCurrent(this.menu, this.menuItem) @@ -358,9 +362,9 @@ Yaml Front Matter with Menu Pages`) {Name: filepath.FromSlash("sect/yaml1.md"), Content: ps1}, {Name: filepath.FromSlash("sect/yaml2.md"), Content: ps2}}) - p1 := s.regularPages[0] + p1 := s.RegularPages[0] assert.Len(t, p1.Menus(), 2, "List YAML") - p2 := s.regularPages[1] + p2 := s.RegularPages[1] assert.Len(t, p2.Menus(), 2, "Map YAML") } @@ -406,14 +410,14 @@ func doTestSectionPagesMenu(canonifyURLs bool, t *testing.T) { viper.Set("canonifyURLs", canonifyURLs) s := setupMenuTests(t, menuPageSectionsSources) - assert.Equal(t, 3, len(s.Sections)) + require.Equal(t, 3, len(s.Sections)) firstSectionPages := s.Sections["first"] - assert.Equal(t, 2, len(firstSectionPages)) + require.Equal(t, 2, len(firstSectionPages)) secondSectionPages := s.Sections["second-section"] - assert.Equal(t, 1, len(secondSectionPages)) + require.Equal(t, 1, len(secondSectionPages)) fishySectionPages := s.Sections["fish-and-chips"] - assert.Equal(t, 1, len(fishySectionPages)) + require.Equal(t, 1, len(fishySectionPages)) nodeFirst := s.getPage(KindSection, "first") require.NotNil(t, nodeFirst) @@ -426,33 +430,33 @@ func doTestSectionPagesMenu(canonifyURLs bool, t *testing.T) { secondSectionMenuEntry := findTestMenuEntryByID(s, "spm", "second-section") fishySectionMenuEntry := findTestMenuEntryByID(s, "spm", "Fish and Chips") - assert.NotNil(t, firstSectionMenuEntry) - assert.NotNil(t, secondSectionMenuEntry) - assert.NotNil(t, nodeFirst) - assert.NotNil(t, nodeSecond) - assert.NotNil(t, fishySectionMenuEntry) - assert.NotNil(t, nodeFishy) + require.NotNil(t, firstSectionMenuEntry) + require.NotNil(t, secondSectionMenuEntry) + require.NotNil(t, nodeFirst) + require.NotNil(t, nodeSecond) + require.NotNil(t, fishySectionMenuEntry) + require.NotNil(t, nodeFishy) - assert.True(t, nodeFirst.IsMenuCurrent("spm", firstSectionMenuEntry)) - assert.False(t, nodeFirst.IsMenuCurrent("spm", secondSectionMenuEntry)) - assert.False(t, nodeFirst.IsMenuCurrent("spm", fishySectionMenuEntry)) - assert.True(t, nodeFishy.IsMenuCurrent("spm", fishySectionMenuEntry)) - assert.Equal(t, "Fish and Chips", fishySectionMenuEntry.Name) + require.True(t, nodeFirst.IsMenuCurrent("spm", firstSectionMenuEntry)) + require.False(t, nodeFirst.IsMenuCurrent("spm", secondSectionMenuEntry)) + require.False(t, nodeFirst.IsMenuCurrent("spm", fishySectionMenuEntry)) + require.True(t, nodeFishy.IsMenuCurrent("spm", fishySectionMenuEntry)) + require.Equal(t, "Fish and Chips", fishySectionMenuEntry.Name) for _, p := range firstSectionPages { - assert.True(t, p.Page.HasMenuCurrent("spm", firstSectionMenuEntry)) - assert.False(t, p.Page.HasMenuCurrent("spm", secondSectionMenuEntry)) + require.True(t, p.Page.HasMenuCurrent("spm", firstSectionMenuEntry)) + require.False(t, p.Page.HasMenuCurrent("spm", secondSectionMenuEntry)) } for _, p := range secondSectionPages { - assert.False(t, p.Page.HasMenuCurrent("spm", firstSectionMenuEntry)) - assert.True(t, p.Page.HasMenuCurrent("spm", secondSectionMenuEntry)) + require.False(t, p.Page.HasMenuCurrent("spm", firstSectionMenuEntry)) + require.True(t, p.Page.HasMenuCurrent("spm", secondSectionMenuEntry)) } for _, p := range fishySectionPages { - assert.False(t, p.Page.HasMenuCurrent("spm", firstSectionMenuEntry)) - assert.False(t, p.Page.HasMenuCurrent("spm", secondSectionMenuEntry)) - assert.True(t, p.Page.HasMenuCurrent("spm", fishySectionMenuEntry)) + require.False(t, p.Page.HasMenuCurrent("spm", firstSectionMenuEntry)) + require.False(t, p.Page.HasMenuCurrent("spm", secondSectionMenuEntry)) + require.True(t, p.Page.HasMenuCurrent("spm", fishySectionMenuEntry)) } } diff --git a/hugolib/node.go b/hugolib/node.go deleted file mode 100644 index 21bdbba5b..000000000 --- a/hugolib/node.go +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright 2015 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" - "html/template" - "path" - "path/filepath" - "strings" - "sync" - "time" - - jww "github.com/spf13/jwalterweatherman" - - "github.com/spf13/hugo/helpers" -) - -// TODO(bep) np clean up node vs page - -type Node struct { - RSSLink template.HTML - Site *SiteInfo `json:"-"` - // layout string - Data map[string]interface{} - Title string - Description string - Keywords []string - Params map[string]interface{} - Date time.Time - Lastmod time.Time - Sitemap Sitemap - URLPath - paginator *Pager - paginatorInit sync.Once - scratch *Scratch - - language *helpers.Language - languageInit sync.Once - lang string -} - -func (n *Node) Now() time.Time { - return time.Now() -} - -func (n *Node) HasMenuCurrent(menuID string, inme *MenuEntry) bool { - if inme.HasChildren() { - me := MenuEntry{Name: n.Title, URL: n.URL()} - - for _, child := range inme.Children { - if me.IsSameResource(child) { - return true - } - if n.HasMenuCurrent(menuID, child) { - return true - } - } - } - - return false -} - -func (n *Node) IsMenuCurrent(menuID string, inme *MenuEntry) bool { - - me := MenuEntry{Name: n.Title, URL: n.Site.createNodeMenuEntryURL(n.URL())} - - if !me.IsSameResource(inme) { - return false - } - - // this resource may be included in several menus - // search for it to make sure that it is in the menu with the given menuId - if menu, ok := (*n.Site.Menus)[menuID]; ok { - for _, menuEntry := range *menu { - if menuEntry.IsSameResource(inme) { - return true - } - - descendantFound := n.isSameAsDescendantMenu(inme, menuEntry) - if descendantFound { - return descendantFound - } - - } - } - - return false -} - -// Param is a convenience method to do lookups in Site's Params map. -// -// This method is also implemented on Page and SiteInfo. -func (n *Node) Param(key interface{}) (interface{}, error) { - return n.Site.Param(key) -} - -func (n *Node) Hugo() *HugoInfo { - return hugoInfo -} - -func (n *Node) isSameAsDescendantMenu(inme *MenuEntry, parent *MenuEntry) bool { - if parent.HasChildren() { - for _, child := range parent.Children { - if child.IsSameResource(inme) { - return true - } - descendantFound := n.isSameAsDescendantMenu(inme, child) - if descendantFound { - return descendantFound - } - } - } - return false -} - -func (n *Node) RSSlink() template.HTML { - return n.RSSLink -} - -func (n *Node) Ref(ref string) (string, error) { - return n.Site.Ref(ref, nil) -} - -func (n *Node) RelRef(ref string) (string, error) { - return n.Site.RelRef(ref, nil) -} - -type URLPath struct { - URL string - Permalink string - Slug string - Section string -} - -func (n *Node) URL() string { - return n.addLangPathPrefix(n.URLPath.URL) -} - -func (n *Node) Permalink() string { - return n.Site.permalink(n.URL()) -} - -// Scratch returns the writable context associated with this Node. -func (n *Node) Scratch() *Scratch { - if n.scratch == nil { - n.scratch = newScratch() - } - return n.scratch -} - -func (n *Node) Language() *helpers.Language { - n.initLanguage() - return n.language -} - -func (n *Node) Lang() string { - // When set, Language can be different from lang in the case where there is a - // content file (doc.sv.md) with language indicator, but there is no language - // config for that language. Then the language will fall back on the site default. - if n.Language() != nil { - return n.Language().Lang - } - return n.lang -} - -func (p *Page) isTranslation(candidate *Page) bool { - if p == candidate || p.Kind != candidate.Kind { - return false - } - - if p.lang != candidate.lang || p.language != p.language { - return false - } - - if p.Kind == KindPage || p.Kind == kindUnknown { - panic("Node type not currently supported for this op") - } - - // At this point, we know that this is a traditional Node (hoe page, section, taxonomy) - // It represents the same node, but different language, if the sections is the same. - if len(p.sections) != len(candidate.sections) { - return false - } - - for i := 0; i < len(p.sections); i++ { - if p.sections[i] != candidate.sections[i] { - return false - } - } - - return true - -} - -func (n *Node) shouldAddLanguagePrefix() bool { - if !n.Site.IsMultiLingual() { - return false - } - - if n.Lang() == "" { - return false - } - - if !n.Site.defaultContentLanguageInSubdir && n.Lang() == n.Site.multilingual.DefaultLang.Lang { - return false - } - - return true -} - -func (n *Node) initLanguage() { - n.languageInit.Do(func() { - if n.language != nil { - return - } - pageLang := n.lang - ml := n.Site.multilingual - if ml == nil { - panic("Multilanguage not set") - } - if pageLang == "" { - n.language = ml.DefaultLang - return - } - - language := ml.Language(pageLang) - - if language == nil { - // It can be a file named stefano.chiodino.md. - jww.WARN.Printf("Page language (if it is that) not found in multilang setup: %s.", pageLang) - language = ml.DefaultLang - } - - n.language = language - }) -} - -func (n *Node) LanguagePrefix() string { - return n.Site.LanguagePrefix -} - -func (n *Node) addLangPathPrefix(outfile string) string { - return n.addLangPathPrefixIfFlagSet(outfile, n.shouldAddLanguagePrefix()) -} - -func (n *Node) addLangPathPrefixIfFlagSet(outfile string, should bool) string { - if helpers.IsAbsURL(outfile) { - return outfile - } - - if !should { - return outfile - } - - hadSlashSuffix := strings.HasSuffix(outfile, "/") - - outfile = "/" + path.Join(n.Lang(), outfile) - if hadSlashSuffix { - outfile += "/" - } - return outfile -} - -func (n *Node) addLangFilepathPrefix(outfile string) string { - if outfile == "" { - outfile = helpers.FilePathSeparator - } - if !n.shouldAddLanguagePrefix() { - return outfile - } - return helpers.FilePathSeparator + filepath.Join(n.Lang(), outfile) -} - -func sectionsFromFilename(filename string) []string { - dir, _ := filepath.Split(filename) - dir = strings.TrimSuffix(dir, helpers.FilePathSeparator) - sections := strings.Split(dir, helpers.FilePathSeparator) - return sections -} - -// TODO(bep) np node identificator -func kindFromFilename(filename string) string { - if !strings.Contains(filename, "_index") { - return KindPage - } - - if strings.HasPrefix(filename, "_index") { - return KindHome - } - - // We don't know enough yet to determine the type. - return kindUnknown -} - -func (p *Page) setNodeTypeVars(s *Site) { - // TODO(bep) np taxonomies etc. - if p.Kind == kindUnknown { - // This is either a taxonomy list, taxonomy term or a section - nodeType := s.nodeTypeFromSections(p.sections) - - if nodeType == kindUnknown { - panic(fmt.Sprintf("Unable to determine node type from %q", p.sections)) - } - - p.Kind = nodeType - } - // TODO(bep) np node URL - // Set Node URL - switch p.Kind { - case KindHome: - p.URLPath.URL = "" - case KindSection: - p.URLPath.URL = p.sections[0] - case KindTaxonomy: - p.URLPath.URL = path.Join(p.sections...) - case KindTaxonomyTerm: - p.URLPath.URL = path.Join(p.sections...) - } - - p.site = s - -} diff --git a/hugolib/node_as_page_test.go b/hugolib/node_as_page_test.go index 1f4fb0b0e..1c091821f 100644 --- a/hugolib/node_as_page_test.go +++ b/hugolib/node_as_page_test.go @@ -84,6 +84,7 @@ func TestNodesAsPage(t *testing.T) { require.True(t, home.IsHome()) require.True(t, home.IsNode()) require.False(t, home.IsPage()) + require.True(t, home.Path() != "") section2 := nodes[3] require.Equal(t, "Section2", section2.Title) @@ -185,6 +186,7 @@ func TestNodesWithNoContentFile(t *testing.T) { homePage := homePages[0] require.Len(t, homePage.Data["Pages"], 9) require.Len(t, homePage.Pages, 9) // Alias + require.True(t, homePage.Path() == "") assertFileContent(t, filepath.Join("public", "index.html"), false, "Index Title: Hugo Rocks!", @@ -280,8 +282,6 @@ title = "Hugo in English" // The en language has content pages - // TODO(bep) np alias URL check - assertFileContent(t, filepath.Join("public", "nn", "index.html"), true, "Index Title: Hugo på norsk") assertFileContent(t, filepath.Join("public", "en", "index.html"), true, @@ -582,7 +582,7 @@ Lastmod: {{ .Lastmod.Format "2006-01-02" }} Taxonomy Terms Title: {{ .Title }} Taxonomy Terms Content: {{ .Content }} {{ range $key, $value := .Data.Terms }} - k/v: {{ $key }} / {{ printf "%=v" $value }} + k/v: {{ $key }} / {{ printf "%s" $value }} {{ end }} Date: {{ .Date.Format "2006-01-02" }} Lastmod: {{ .Lastmod.Format "2006-01-02" }} diff --git a/hugolib/page.go b/hugolib/page.go index 73924587b..cc2b9110d 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -86,27 +86,35 @@ type Page struct { // This collection will be nil for regular pages. Pages Pages - Params map[string]interface{} - Content template.HTML - Summary template.HTML - Aliases []string - Status string - Images []Image - Videos []Video - TableOfContents template.HTML - Truncated bool - Draft bool - PublishDate time.Time - ExpiryDate time.Time - Markup string - translations Pages - extension string - contentType string - renderable bool + Params map[string]interface{} + Content template.HTML + Summary template.HTML + Aliases []string + Status string + Images []Image + Videos []Video + + TableOfContents template.HTML + + Truncated bool + Draft bool + + PublishDate time.Time + ExpiryDate time.Time + + Markup string + + translations Pages + + extension string + contentType string + renderable bool + Layout string layoutsCalculated []string - linkTitle string - frontmatter []byte + + linkTitle string + frontmatter []byte // rawContent isn't "raw" as in the same as in the content file. // Hugo cares about memory consumption, so we make changes to it to do @@ -132,9 +140,6 @@ type Page struct { Source Position `json:"-"` - // TODO(bep) np pointer, or remove - Node - GitInfo *gitmap.GitInfo // This was added as part of getting the Nodes (taxonomies etc.) to work as @@ -151,6 +156,32 @@ type Page struct { // TODO(bep) np Site added to page, keep? site *Site + + // Pulled over from Node. TODO(bep) np reorg and group (embed) + + Site *SiteInfo `json:"-"` + + Title string + Description string + Keywords []string + Data map[string]interface{} + + Date time.Time + Lastmod time.Time + + Sitemap Sitemap + + RSSLink template.HTML + URLPath + + paginator *Pager + paginatorInit sync.Once + + scratch *Scratch + + language *helpers.Language + languageInit sync.Once + lang string } // IsNode returns whether this is an item of one of the list types in Hugo, @@ -207,6 +238,10 @@ type Position struct { type Pages []*Page +func (p Pages) String() string { + return fmt.Sprintf("Pages(%d)", len(p)) +} + func (ps Pages) FindPagePosByFilePath(inPath string) int { for i, x := range ps { if x.Source.Path() == inPath { @@ -300,14 +335,6 @@ func (p *Page) UniqueID() string { return p.Source.UniqueID() } -func (p *Page) Ref(ref string) (string, error) { - return p.Node.Site.Ref(ref, p) -} - -func (p *Page) RelRef(ref string) (string, error) { - return p.Node.Site.RelRef(ref, p) -} - // for logging func (p *Page) lineNumRawContentStart() int { return bytes.Count(p.frontmatter, []byte("\n")) + 1 @@ -450,10 +477,10 @@ func (p *Page) renderContent(content []byte) []byte { var fileFn helpers.FileResolverFunc if p.getRenderingConfig().SourceRelativeLinksEval { fn = func(ref string) (string, error) { - return p.Node.Site.SourceRelativeLink(ref, p) + return p.Site.SourceRelativeLink(ref, p) } fileFn = func(ref string) (string, error) { - return p.Node.Site.SourceRelativeLinkFile(ref, p) + return p.Site.SourceRelativeLinkFile(ref, p) } } return helpers.RenderBytes(&helpers.RenderingContext{ @@ -483,10 +510,10 @@ func (p *Page) getRenderingConfig() *helpers.Blackfriday { func newPage(filename string) *Page { page := Page{ - Kind: kindFromFilename(filename), - contentType: "", - Source: Source{File: *source.NewFile(filename)}, - Node: Node{Keywords: []string{}, Sitemap: Sitemap{Priority: -1}}, + Kind: kindFromFilename(filename), + contentType: "", + Source: Source{File: *source.NewFile(filename)}, + Keywords: []string{}, Sitemap: Sitemap{Priority: -1}, Params: make(map[string]interface{}), translations: make(Pages, 0), sections: sectionsFromFilename(filename), @@ -778,7 +805,7 @@ func (p *Page) IsExpired() bool { func (p *Page) Permalink() (string, error) { // TODO(bep) np permalink if p.IsNode() { - return p.Node.Permalink(), nil + return p.Site.permalink(p.URL()), nil } link, err := p.permalink() if err != nil { @@ -788,6 +815,10 @@ func (p *Page) Permalink() (string, error) { } func (p *Page) URL() string { + // TODO(bep np URL + if p.IsNode() { + return p.addLangPathPrefix(p.URLPath.URL) + } if p.URLPath.URL != "" { // This is the url set in front matter return p.URLPath.URL @@ -1013,29 +1044,48 @@ func (p *Page) getParam(key string, stringToLower bool) interface{} { return nil } -func (p *Page) HasMenuCurrent(menu string, me *MenuEntry) bool { - // TODO(bep) np menu - if p.IsNode() { - return p.Node.HasMenuCurrent(menu, me) - } - menus := p.Menus() +func (p *Page) HasMenuCurrent(menuID string, me *MenuEntry) bool { + sectionPagesMenu := helpers.Config().GetString("SectionPagesMenu") // page is labeled as "shadow-member" of the menu with the same identifier as the section - if sectionPagesMenu != "" && p.Section() != "" && sectionPagesMenu == menu && p.Section() == me.Identifier { + if sectionPagesMenu != "" && p.Section() != "" && sectionPagesMenu == menuID && p.Section() == me.Identifier { return true } - if m, ok := menus[menu]; ok { - if me.HasChildren() { - for _, child := range me.Children { - if child.IsEqual(m) { - return true - } - if p.HasMenuCurrent(menu, child) { - return true - } + if !me.HasChildren() { + return false + } + + menus := p.Menus() + + if m, ok := menus[menuID]; ok { + + for _, child := range me.Children { + if child.IsEqual(m) { + return true } + if p.HasMenuCurrent(menuID, child) { + return true + } + } + + } + + if p.IsPage() { + return false + } + + // The following logic is kept from back when Hugo had both Page and Node types. + // TODO(bep) consolidate / clean + nme := MenuEntry{Name: p.Title, URL: p.URL()} + + for _, child := range me.Children { + if nme.IsSameResource(child) { + return true + } + if p.HasMenuCurrent(menuID, child) { + return true } } @@ -1043,17 +1093,59 @@ func (p *Page) HasMenuCurrent(menu string, me *MenuEntry) bool { } -func (p *Page) IsMenuCurrent(menu string, inme *MenuEntry) bool { - // TODO(bep) np menu - if p.IsNode() { - return p.Node.IsMenuCurrent(menu, inme) - } +func (p *Page) IsMenuCurrent(menuID string, inme *MenuEntry) bool { + menus := p.Menus() - if me, ok := menus[menu]; ok { - return me.IsEqual(inme) + if me, ok := menus[menuID]; ok { + if me.IsEqual(inme) { + return true + } } + if p.IsPage() { + return false + } + + // The following logic is kept from back when Hugo had both Page and Node types. + // TODO(bep) consolidate / clean + me := MenuEntry{Name: p.Title, URL: p.Site.createNodeMenuEntryURL(p.URL())} + + if !me.IsSameResource(inme) { + return false + } + + // this resource may be included in several menus + // search for it to make sure that it is in the menu with the given menuId + if menu, ok := (*p.Site.Menus)[menuID]; ok { + for _, menuEntry := range *menu { + if menuEntry.IsSameResource(inme) { + return true + } + + descendantFound := p.isSameAsDescendantMenu(inme, menuEntry) + if descendantFound { + return descendantFound + } + + } + } + + return false +} + +func (p *Page) isSameAsDescendantMenu(inme *MenuEntry, parent *MenuEntry) bool { + if parent.HasChildren() { + for _, child := range parent.Children { + if child.IsSameResource(inme) { + return true + } + descendantFound := p.isSameAsDescendantMenu(inme, child) + if descendantFound { + return descendantFound + } + } + } return false } @@ -1253,7 +1345,6 @@ func (p *Page) FullFilePath() string { func (p *Page) TargetPath() (outfile string) { - // TODO(bep) np switch p.Kind { case KindHome: return p.addLangFilepathPrefix(helpers.FilePathSeparator) @@ -1416,7 +1507,7 @@ func (p *Page) updatePageDates() { // the paginators etc., we do it manually here. // TODO(bep) np do better func (p *Page) copy() *Page { - c := &Page{Kind: p.Kind, Node: Node{Site: p.Site}} + c := &Page{Kind: p.Kind, Site: p.Site} c.Title = p.Title c.Data = p.Data c.Date = p.Date @@ -1426,3 +1517,217 @@ func (p *Page) copy() *Page { c.URLPath = p.URLPath return c } + +// TODO(bep) np these are pulled over from Node. Needs regrouping / embed + +func (p *Page) Now() time.Time { + return time.Now() +} + +func (p *Page) Hugo() *HugoInfo { + return hugoInfo +} + +func (p *Page) RSSlink() template.HTML { + // TODO(bep) we cannot have two of these + helpers.Deprecated(".Page", "RSSlink", "RSSLink") + return p.RSSLink +} + +func (p *Page) Ref(ref string) (string, error) { + return p.Site.Ref(ref, nil) +} + +func (p *Page) RelRef(ref string) (string, error) { + return p.Site.RelRef(ref, nil) +} + +func (p *Page) String() string { + return fmt.Sprintf("Page(%q)", p.Title) +} + +type URLPath struct { + URL string + Permalink string + Slug string + Section string +} + +// Scratch returns the writable context associated with this Page. +func (p *Page) Scratch() *Scratch { + if p.scratch == nil { + p.scratch = newScratch() + } + return p.scratch +} + +func (p *Page) Language() *helpers.Language { + p.initLanguage() + return p.language +} + +func (p *Page) Lang() string { + // When set, Language can be different from lang in the case where there is a + // content file (doc.sv.md) with language indicator, but there is no language + // config for that language. Then the language will fall back on the site default. + if p.Language() != nil { + return p.Language().Lang + } + return p.lang +} + +func (p *Page) isTranslation(candidate *Page) bool { + if p == candidate || p.Kind != candidate.Kind { + return false + } + + if p.lang != candidate.lang || p.language != p.language { + return false + } + + if p.Kind == KindPage || p.Kind == kindUnknown { + panic("Node type not currently supported for this op") + } + + // At this point, we know that this is a traditional Node (home page, section, taxonomy) + // It represents the same node, but different language, if the sections is the same. + if len(p.sections) != len(candidate.sections) { + return false + } + + for i := 0; i < len(p.sections); i++ { + if p.sections[i] != candidate.sections[i] { + return false + } + } + + return true + +} + +func (p *Page) shouldAddLanguagePrefix() bool { + if !p.Site.IsMultiLingual() { + return false + } + + if p.Lang() == "" { + return false + } + + if !p.Site.defaultContentLanguageInSubdir && p.Lang() == p.Site.multilingual.DefaultLang.Lang { + return false + } + + return true +} + +func (p *Page) initLanguage() { + p.languageInit.Do(func() { + if p.language != nil { + return + } + pageLang := p.lang + ml := p.Site.multilingual + if ml == nil { + panic("Multilanguage not set") + } + if pageLang == "" { + p.language = ml.DefaultLang + return + } + + language := ml.Language(pageLang) + + if language == nil { + // It can be a file named stefano.chiodino.md. + jww.WARN.Printf("Page language (if it is that) not found in multilang setup: %s.", pageLang) + language = ml.DefaultLang + } + + p.language = language + }) +} + +func (p *Page) LanguagePrefix() string { + return p.Site.LanguagePrefix +} + +func (p *Page) addLangPathPrefix(outfile string) string { + return p.addLangPathPrefixIfFlagSet(outfile, p.shouldAddLanguagePrefix()) +} + +func (p *Page) addLangPathPrefixIfFlagSet(outfile string, should bool) string { + if helpers.IsAbsURL(outfile) { + return outfile + } + + if !should { + return outfile + } + + hadSlashSuffix := strings.HasSuffix(outfile, "/") + + outfile = "/" + path.Join(p.Lang(), outfile) + if hadSlashSuffix { + outfile += "/" + } + return outfile +} + +func (p *Page) addLangFilepathPrefix(outfile string) string { + if outfile == "" { + outfile = helpers.FilePathSeparator + } + if !p.shouldAddLanguagePrefix() { + return outfile + } + return helpers.FilePathSeparator + filepath.Join(p.Lang(), outfile) +} + +func sectionsFromFilename(filename string) []string { + dir, _ := filepath.Split(filename) + dir = strings.TrimSuffix(dir, helpers.FilePathSeparator) + sections := strings.Split(dir, helpers.FilePathSeparator) + return sections +} + +func kindFromFilename(filename string) string { + if !strings.Contains(filename, "_index") { + return KindPage + } + + if strings.HasPrefix(filename, "_index") { + return KindHome + } + + // We don't know enough yet to determine the type. + return kindUnknown +} + +func (p *Page) setNodeTypeVars(s *Site) { + if p.Kind == kindUnknown { + // This is either a taxonomy list, taxonomy term or a section + nodeType := s.nodeTypeFromSections(p.sections) + + if nodeType == kindUnknown { + panic(fmt.Sprintf("Unable to determine node type from %q", p.sections)) + } + + p.Kind = nodeType + } + // TODO(bep) np node URL + // Set Node URL + switch p.Kind { + case KindHome: + p.URLPath.URL = "" + case KindSection: + p.URLPath.URL = p.sections[0] + case KindTaxonomy: + p.URLPath.URL = path.Join(p.sections...) + case KindTaxonomyTerm: + p.URLPath.URL = path.Join(p.sections...) + } + + p.site = s + +} diff --git a/hugolib/pageSort_test.go b/hugolib/pageSort_test.go index d98018f38..7ecbee98a 100644 --- a/hugolib/pageSort_test.go +++ b/hugolib/pageSort_test.go @@ -147,13 +147,12 @@ func createSortTestPages(num int) Pages { for i := 0; i < num; i++ { pages[i] = &Page{ - Node: Node{ - URLPath: URLPath{ - Section: "z", - URL: fmt.Sprintf("http://base/x/y/p%d.html", i), - }, - Site: &info, + + URLPath: URLPath{ + Section: "z", + URL: fmt.Sprintf("http://base/x/y/p%d.html", i), }, + Site: &info, Source: Source{File: *source.NewFile(filepath.FromSlash(fmt.Sprintf("/x/y/p%d.md", i)))}, } w := 5 diff --git a/hugolib/page_collections.go b/hugolib/page_collections.go index 84e77bdd7..d8fe13abc 100644 --- a/hugolib/page_collections.go +++ b/hugolib/page_collections.go @@ -32,8 +32,7 @@ type PageCollections struct { // A convenience cache for the regular pages. // This is for the current language only. - // TODO(bep) np consider exporting this - regularPages Pages + RegularPages Pages // Includes absolute all pages (of all types), including drafts etc. rawAllPages Pages @@ -41,7 +40,7 @@ type PageCollections struct { func (c *PageCollections) refreshPageCaches() { c.indexPages = c.findPagesByNodeTypeNotIn(KindPage, c.Pages) - c.regularPages = c.findPagesByNodeTypeIn(KindPage, c.Pages) + c.RegularPages = c.findPagesByNodeTypeIn(KindPage, c.Pages) // TODO(bep) np remove eventually for _, n := range c.Pages { diff --git a/hugolib/page_permalink_test.go b/hugolib/page_permalink_test.go index f025c4f4f..13a9311f3 100644 --- a/hugolib/page_permalink_test.go +++ b/hugolib/page_permalink_test.go @@ -67,13 +67,11 @@ func TestPermalink(t *testing.T) { p := &Page{ Kind: KindPage, - Node: Node{ - URLPath: URLPath{ - Section: "z", - URL: test.url, - }, - Site: &info, + URLPath: URLPath{ + Section: "z", + URL: test.url, }, + Site: &info, Source: Source{File: *source.NewFile(filepath.FromSlash(test.file))}, } diff --git a/hugolib/page_test.go b/hugolib/page_test.go index 8530759d6..45ca241fd 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -630,9 +630,9 @@ func testAllMarkdownEnginesForPages(t *testing.T, t.Fatalf("Failed to build site: %s", err) } - require.Len(t, s.regularPages, len(pageSources)) + require.Len(t, s.RegularPages, len(pageSources)) - assertFunc(t, e.ext, s.regularPages) + assertFunc(t, e.ext, s.RegularPages) } @@ -740,9 +740,9 @@ func TestPageWithDelimiterForMarkdownThatCrossesBorder(t *testing.T) { t.Fatalf("Failed to build site: %s", err) } - require.Len(t, s.regularPages, 1) + require.Len(t, s.RegularPages, 1) - p := s.regularPages[0] + p := s.RegularPages[0] if p.Summary != template.HTML("

The best static site generator.1\n

") { t.Fatalf("Got summary:\n%q", p.Summary) @@ -788,9 +788,9 @@ func TestPageWithAdditionalExtension(t *testing.T) { t.Fatalf("Failed to build site: %s", err) } - require.Len(t, s.regularPages, 1) + require.Len(t, s.RegularPages, 1) - p := s.regularPages[0] + p := s.RegularPages[0] checkPageContent(t, p, "

first line.
\nsecond line.

\n\n

fourth line.

\n") } @@ -802,9 +802,9 @@ func TestTableOfContents(t *testing.T) { t.Fatalf("Failed to build site: %s", err) } - require.Len(t, s.regularPages, 1) + require.Len(t, s.RegularPages, 1) - p := s.regularPages[0] + p := s.RegularPages[0] checkPageContent(t, p, "\n\n

For some moments the old man did not reply. He stood with bowed head, buried in deep thought. But at last he spoke.

\n\n

AA

\n\n

I have no idea, of course, how long it took me to reach the limit of the plain,\nbut at last I entered the foothills, following a pretty little canyon upward\ntoward the mountains. Beside me frolicked a laughing brooklet, hurrying upon\nits noisy way down to the silent sea. In its quieter pools I discovered many\nsmall fish, of four-or five-pound weight I should imagine. In appearance,\nexcept as to size and color, they were not unlike the whale of our own seas. As\nI watched them playing about I discovered, not only that they suckled their\nyoung, but that at intervals they rose to the surface to breathe as well as to\nfeed upon certain grasses and a strange, scarlet lichen which grew upon the\nrocks just above the water line.

\n\n

AAA

\n\n

I remember I felt an extraordinary persuasion that I was being played with,\nthat presently, when I was upon the very verge of safety, this mysterious\ndeath–as swift as the passage of light–would leap after me from the pit about\nthe cylinder and strike me down. ## BB

\n\n

BBB

\n\n

“You’re a great Granser,” he cried delightedly, “always making believe them little marks mean something.”

\n") checkPageTOC(t, p, "") @@ -832,9 +832,9 @@ func TestPageWithDate(t *testing.T) { t.Fatalf("Failed to build site: %s", err) } - require.Len(t, s.regularPages, 1) + require.Len(t, s.RegularPages, 1) - p := s.regularPages[0] + p := s.RegularPages[0] d, _ := time.Parse(time.RFC3339, "2013-05-17T16:59:30Z") checkPageDate(t, p, d) @@ -1145,10 +1145,10 @@ func TestPagePaths(t *testing.T) { for _, test := range tests { p, _ := NewPageFrom(strings.NewReader(test.content), filepath.FromSlash(test.path)) info := newSiteInfo(siteBuilderCfg{language: helpers.NewDefaultLanguage()}) - p.Node.Site = &info + p.Site = &info if test.hasPermalink { - p.Node.Site.Permalinks = siteParmalinksSetting + p.Site.Permalinks = siteParmalinksSetting } expectedTargetPath := filepath.FromSlash(test.expected) @@ -1263,7 +1263,7 @@ func TestIndexPageSimpleMethods(t *testing.T) { }{ {func(n *Page) bool { return n.IsNode() }}, {func(n *Page) bool { return !n.IsPage() }}, - {func(n *Page) bool { return n.RSSlink() == "rssLink" }}, + {func(n *Page) bool { return n.RSSLink == "rssLink" }}, {func(n *Page) bool { return n.Scratch() != nil }}, {func(n *Page) bool { return n.Hugo() != nil }}, {func(n *Page) bool { return n.Now().Unix() == time.Now().Unix() }}, @@ -1298,9 +1298,9 @@ func TestChompBOM(t *testing.T) { t.Fatalf("Failed to build site: %s", err) } - require.Len(t, s.regularPages, 1) + require.Len(t, s.RegularPages, 1) - p := s.regularPages[0] + p := s.RegularPages[0] checkPageTitle(t, p, "Simple") } diff --git a/hugolib/pagination.go b/hugolib/pagination.go index 3e3bb59c6..93fe50078 100644 --- a/hugolib/pagination.go +++ b/hugolib/pagination.go @@ -33,6 +33,10 @@ type Pager struct { *paginator } +func (p Pager) String() string { + return fmt.Sprintf("Pager %d", p.number) +} + type paginatedElement interface { Len() int } @@ -257,11 +261,11 @@ func splitPageGroups(pageGroups PagesGroup, size int) []paginatedElement { return split } -// Paginator gets this Node's paginator if it's already created. +// Paginator gets this Page's paginator if it's already created. // If it's not, one will be created with all pages in Data["Pages"]. -func (n *Page) Paginator(options ...interface{}) (*Pager, error) { - if !n.IsNode() { - return nil, fmt.Errorf("Paginators not supported for pages of type %q (%q)", n.Kind, n.Title) +func (p *Page) Paginator(options ...interface{}) (*Pager, error) { + if !p.IsNode() { + return nil, fmt.Errorf("Paginators not supported for pages of type %q (%q)", p.Kind, p.Title) } pagerSize, err := resolvePagerSize(options...) @@ -271,12 +275,12 @@ func (n *Page) Paginator(options ...interface{}) (*Pager, error) { var initError error - n.paginatorInit.Do(func() { - if n.paginator != nil { + p.paginatorInit.Do(func() { + if p.paginator != nil { return } - pagers, err := paginatePages(n.Data["Pages"], pagerSize, n.URL()) + pagers, err := paginatePages(p.Data["Pages"], pagerSize, p.URL()) if err != nil { initError = err @@ -284,10 +288,10 @@ func (n *Page) Paginator(options ...interface{}) (*Pager, error) { if len(pagers) > 0 { // the rest of the nodes will be created later - n.paginator = pagers[0] - n.paginator.source = "paginator" - n.paginator.options = options - n.Site.addToPaginationPageCount(uint64(n.paginator.TotalPages())) + p.paginator = pagers[0] + p.paginator.source = "paginator" + p.paginator.options = options + p.Site.addToPaginationPageCount(uint64(p.paginator.TotalPages())) } }) @@ -296,7 +300,7 @@ func (n *Page) Paginator(options ...interface{}) (*Pager, error) { return nil, initError } - return n.paginator, nil + return p.paginator, nil } // Paginate gets this Node's paginator if it's already created. diff --git a/hugolib/pagination_test.go b/hugolib/pagination_test.go index 7cd94259f..591d09047 100644 --- a/hugolib/pagination_test.go +++ b/hugolib/pagination_test.go @@ -457,13 +457,11 @@ func createTestPages(num int) Pages { info := newSiteInfo(siteBuilderCfg{baseURL: "http://base/", language: helpers.NewDefaultLanguage()}) for i := 0; i < num; i++ { pages[i] = &Page{ - Node: Node{ - URLPath: URLPath{ - Section: "z", - URL: fmt.Sprintf("http://base/x/y/p%d.html", i), - }, - Site: &info, + URLPath: URLPath{ + Section: "z", + URL: fmt.Sprintf("http://base/x/y/p%d.html", i), }, + Site: &info, Source: Source{File: *source.NewFile(filepath.FromSlash(fmt.Sprintf("/x/y/p%d.md", i)))}, } w := 5 diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go index d8b8b411a..3ea9ed4e6 100644 --- a/hugolib/shortcode_test.go +++ b/hugolib/shortcode_test.go @@ -69,9 +69,9 @@ title: "Title" t.Fatalf("No error from shortcode") } - require.Len(t, h.Sites[0].regularPages, 1) + require.Len(t, h.Sites[0].RegularPages, 1) - output := strings.TrimSpace(string(h.Sites[0].regularPages[0].Content)) + output := strings.TrimSpace(string(h.Sites[0].RegularPages[0].Content)) if strings.HasPrefix(output, "

") { output = output[3:] } diff --git a/hugolib/site.go b/hugolib/site.go index c8d38b909..771256b17 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -193,6 +193,10 @@ type SiteInfo struct { pathSpec *helpers.PathSpec } +func (s *SiteInfo) String() string { + return fmt.Sprintf("Site(%q)", s.Title) +} + // Used in tests. type siteBuilderCfg struct { diff --git a/hugolib/siteJSONEncode_test.go b/hugolib/siteJSONEncode_test.go index 9e2f6ecc2..170db4b4d 100644 --- a/hugolib/siteJSONEncode_test.go +++ b/hugolib/siteJSONEncode_test.go @@ -30,7 +30,7 @@ func TestEncodePage(t *testing.T) { _, err := json.Marshal(s) check(t, err) - _, err = json.Marshal(s.regularPages[0]) + _, err = json.Marshal(s.RegularPages[0]) check(t, err) } diff --git a/hugolib/site_render.go b/hugolib/site_render.go index 6b471b0bd..d9f718a7a 100644 --- a/hugolib/site_render.go +++ b/hugolib/site_render.go @@ -99,7 +99,8 @@ func (s *Site) renderPaginator(p *Page) error { aliasPath := p.addLangPathPrefix(helpers.PaginateAliasPath(path.Join(p.sections...), 1)) //TODO(bep) np node.permalink - s.writeDestAlias(aliasPath, p.Node.Permalink(), nil) + link, _ := p.Permalink() + s.writeDestAlias(aliasPath, link, nil) pagers := p.paginator.Pagers() diff --git a/hugolib/site_test.go b/hugolib/site_test.go index 0302f3503..440f4bd7c 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -91,9 +91,9 @@ func TestDegenerateRenderThingMissingTemplate(t *testing.T) { t.Fatalf("Failed to build site: %s", err) } - require.Len(t, s.regularPages, 1) + require.Len(t, s.RegularPages, 1) - p := s.regularPages[0] + p := s.RegularPages[0] err := s.renderThing(p, "foobar", nil) if err == nil { @@ -142,14 +142,14 @@ func TestDraftAndFutureRender(t *testing.T) { // Testing Defaults.. Only draft:true and publishDate in the past should be rendered s := siteSetup(t) - if len(s.regularPages) != 1 { + if len(s.RegularPages) != 1 { t.Fatal("Draft or Future dated content published unexpectedly") } // only publishDate in the past should be rendered viper.Set("buildDrafts", true) s = siteSetup(t) - if len(s.regularPages) != 2 { + if len(s.RegularPages) != 2 { t.Fatal("Future Dated Posts published unexpectedly") } @@ -157,7 +157,7 @@ func TestDraftAndFutureRender(t *testing.T) { viper.Set("buildDrafts", false) viper.Set("buildFuture", true) s = siteSetup(t) - if len(s.regularPages) != 2 { + if len(s.RegularPages) != 2 { t.Fatal("Draft posts published unexpectedly") } @@ -165,7 +165,7 @@ func TestDraftAndFutureRender(t *testing.T) { viper.Set("buildDrafts", true) viper.Set("buildFuture", true) s = siteSetup(t) - if len(s.regularPages) != 4 { + if len(s.RegularPages) != 4 { t.Fatal("Drafts or Future posts not included as expected") } @@ -201,11 +201,11 @@ func TestFutureExpirationRender(t *testing.T) { s := siteSetup(t) if len(s.AllPages) != 1 { - if len(s.regularPages) > 1 { + if len(s.RegularPages) > 1 { t.Fatal("Expired content published unexpectedly") } - if len(s.regularPages) < 1 { + if len(s.RegularPages) < 1 { t.Fatal("Valid content expired unexpectedly") } } @@ -285,7 +285,7 @@ THE END.`, refShortcode)), t.Fatalf("Failed to build site: %s", err) } - if len(s.regularPages) != 3 { + if len(s.RegularPages) != 3 { t.Fatalf("Expected 3 got %d pages", len(s.AllPages)) } @@ -377,7 +377,7 @@ func doTestShouldAlwaysHaveUglyURLs(t *testing.T, uglyURLs bool) { {filepath.FromSlash("public/ugly.html"), "\n\n

title

\n\n

doc2 content

\n"}, } - for _, p := range s.regularPages { + for _, p := range s.RegularPages { assert.False(t, p.IsHome()) } @@ -649,7 +649,7 @@ func TestOrderedPages(t *testing.T) { t.Errorf("Pages in unexpected order. Second should be '%s', got '%s'", "Three", s.Sections["sect"][1].Page.Title) } - bydate := s.regularPages.ByDate() + bydate := s.RegularPages.ByDate() if bydate[0].Title != "One" { t.Errorf("Pages in unexpected order. First should be '%s', got '%s'", "One", bydate[0].Title) @@ -660,7 +660,7 @@ func TestOrderedPages(t *testing.T) { t.Errorf("Pages in unexpected order. First should be '%s', got '%s'", "Three", rev[0].Title) } - bypubdate := s.regularPages.ByPublishDate() + bypubdate := s.RegularPages.ByPublishDate() if bypubdate[0].Title != "One" { t.Errorf("Pages in unexpected order. First should be '%s', got '%s'", "One", bypubdate[0].Title) @@ -671,7 +671,7 @@ func TestOrderedPages(t *testing.T) { t.Errorf("Pages in unexpected order. First should be '%s', got '%s'", "Three", rbypubdate[0].Title) } - bylength := s.regularPages.ByLength() + bylength := s.RegularPages.ByLength() if bylength[0].Title != "One" { t.Errorf("Pages in unexpected order. First should be '%s', got '%s'", "One", bylength[0].Title) } @@ -710,7 +710,7 @@ func TestGroupedPages(t *testing.T) { t.Fatalf("Failed to build site: %s", err) } - rbysection, err := s.regularPages.GroupBy("Section", "desc") + rbysection, err := s.RegularPages.GroupBy("Section", "desc") if err != nil { t.Fatalf("Unable to make PageGroup array: %s", err) } @@ -730,7 +730,7 @@ func TestGroupedPages(t *testing.T) { t.Errorf("PageGroup has unexpected number of pages. Third group should have '%d' pages, got '%d' pages", 2, len(rbysection[2].Pages)) } - bytype, err := s.regularPages.GroupBy("Type", "asc") + bytype, err := s.RegularPages.GroupBy("Type", "asc") if err != nil { t.Fatalf("Unable to make PageGroup array: %s", err) } @@ -750,7 +750,7 @@ func TestGroupedPages(t *testing.T) { t.Errorf("PageGroup has unexpected number of pages. First group should have '%d' pages, got '%d' pages", 2, len(bytype[2].Pages)) } - bydate, err := s.regularPages.GroupByDate("2006-01", "asc") + bydate, err := s.RegularPages.GroupByDate("2006-01", "asc") if err != nil { t.Fatalf("Unable to make PageGroup array: %s", err) } @@ -770,7 +770,7 @@ func TestGroupedPages(t *testing.T) { t.Errorf("PageGroup has unexpected number of pages. First group should have '%d' pages, got '%d' pages", 2, len(bydate[2].Pages)) } - bypubdate, err := s.regularPages.GroupByPublishDate("2006") + bypubdate, err := s.RegularPages.GroupByPublishDate("2006") if err != nil { t.Fatalf("Unable to make PageGroup array: %s", err) } @@ -787,7 +787,7 @@ func TestGroupedPages(t *testing.T) { t.Errorf("PageGroup has unexpected number of pages. First group should have '%d' pages, got '%d' pages", 3, len(bypubdate[0].Pages)) } - byparam, err := s.regularPages.GroupByParam("my_param", "desc") + byparam, err := s.RegularPages.GroupByParam("my_param", "desc") if err != nil { t.Fatalf("Unable to make PageGroup array: %s", err) } @@ -807,12 +807,12 @@ func TestGroupedPages(t *testing.T) { t.Errorf("PageGroup has unexpected number of pages. First group should have '%d' pages, got '%d' pages", 2, len(byparam[0].Pages)) } - _, err = s.regularPages.GroupByParam("not_exist") + _, err = s.RegularPages.GroupByParam("not_exist") if err == nil { t.Errorf("GroupByParam didn't return an expected error") } - byOnlyOneParam, err := s.regularPages.GroupByParam("only_one") + byOnlyOneParam, err := s.RegularPages.GroupByParam("only_one") if err != nil { t.Fatalf("Unable to make PageGroup array: %s", err) } @@ -823,7 +823,7 @@ func TestGroupedPages(t *testing.T) { t.Errorf("PageGroup array in unexpected order. First group key should be '%s', got '%s'", "yes", byOnlyOneParam[0].Key) } - byParamDate, err := s.regularPages.GroupByParamDate("my_date", "2006-01") + byParamDate, err := s.RegularPages.GroupByParamDate("my_date", "2006-01") if err != nil { t.Fatalf("Unable to make PageGroup array: %s", err) } diff --git a/hugolib/taxonomy.go b/hugolib/taxonomy.go index 112d22b37..68354de89 100644 --- a/hugolib/taxonomy.go +++ b/hugolib/taxonomy.go @@ -14,6 +14,7 @@ package hugolib import ( + "fmt" "sort" "github.com/spf13/hugo/helpers" @@ -23,6 +24,10 @@ import ( // e.g. List['tags'] => TagTaxonomy (from above) type TaxonomyList map[string]Taxonomy +func (tl TaxonomyList) String() string { + return fmt.Sprintf("TaxonomyList(%d)", len(tl)) +} + // A Taxonomy is a map of keywords to a list of pages. // For example // TagTaxonomy['technology'] = WeightedPages @@ -39,6 +44,10 @@ type WeightedPage struct { Page *Page } +func (w WeightedPage) String() string { + return fmt.Sprintf("WeightedPage(%d,%q)", w.Weight, w.Page.Title) +} + // OrderedTaxonomy is another representation of an Taxonomy using an array rather than a map. // Important because you can't order a map. type OrderedTaxonomy []OrderedTaxonomyEntry