summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-07-17 11:18:29 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-07-18 00:07:20 +0200
commit3eb313fef495a39731dafa6bddbf77760090230d (patch)
treeaa93e04123fa299e27b4d701b81d7976865d299c
parentb93417aa1d3d38a9e56bad25937e0e638a113faf (diff)
Simplify .Site.GetPage etc.
This commit is a follow up to a recent overhaul of the GetPage/ref/relref implemenation. The most important change in this commit is the update to `.Site.GetPage`: * To reduce the amount of breakage in the wild to its minimum, I have reworked .Site.GetPage with some rules: * We cannot support more than 2 arguments, i.e. .Site.GetPage "page" "posts" "mypage.md" will now throw an error. I think this is the most uncommon syntax and should be OK. It is an easy fix to change the above to .Site.GetPage "/posts/mypage.md" or similar. * .Site.GetPage "home", .Site.GetPage "home" "" and .Site.GetPage "home" "/" will give you the home page. This means that if you have page in root with the name home.md you need to do .Site.GetPage "/home.md" or similar This commit also fixes some multilingual issues, most notable it is now possible to do cross-language ref/relref lookups by prepending the language code to the path, e.g. `/jp/posts/mypage.md`. This commit also reverts the site building tests related to this to "Hugo 0.44 state", to get better control of the changes made. Closes #4147 Closes #4727 Closes #4728 Closes #4728 Closes #4726 Closes #4652
-rw-r--r--cache/partitioned_lazy_cache.go41
-rw-r--r--hugolib/disableKinds_test.go12
-rw-r--r--hugolib/hugo_sites_build_test.go30
-rw-r--r--hugolib/hugo_sites_multihost_test.go10
-rw-r--r--hugolib/language_content_dir_test.go25
-rw-r--r--hugolib/page.go26
-rw-r--r--hugolib/page_bundler_test.go50
-rw-r--r--hugolib/page_collections.go171
-rw-r--r--hugolib/page_collections_test.go15
-rw-r--r--hugolib/pages_language_merge_test.go4
-rw-r--r--hugolib/shortcode_test.go2
-rw-r--r--hugolib/site.go47
-rw-r--r--hugolib/site_output_test.go4
-rw-r--r--hugolib/site_sections_test.go31
-rw-r--r--hugolib/site_test.go19
-rw-r--r--hugolib/site_url_test.go6
-rw-r--r--hugolib/taxonomy_test.go12
17 files changed, 282 insertions, 223 deletions
diff --git a/cache/partitioned_lazy_cache.go b/cache/partitioned_lazy_cache.go
index 9baf0377d..31e66e127 100644
--- a/cache/partitioned_lazy_cache.go
+++ b/cache/partitioned_lazy_cache.go
@@ -24,34 +24,52 @@ type Partition struct {
Load func() (map[string]interface{}, error)
}
-type lazyPartition struct {
+// Lazy represents a lazily loaded cache.
+type Lazy struct {
initSync sync.Once
+ initErr error
cache map[string]interface{}
load func() (map[string]interface{}, error)
}
-func (l *lazyPartition) init() error {
- var err error
+// NewLazy creates a lazy cache with the given load func.
+func NewLazy(load func() (map[string]interface{}, error)) *Lazy {
+ return &Lazy{load: load}
+}
+
+func (l *Lazy) init() error {
l.initSync.Do(func() {
- var c map[string]interface{}
- c, err = l.load()
+ c, err := l.load()
l.cache = c
+ l.initErr = err
+
})
- return err
+ return l.initErr
+}
+
+// Get initializes the cache if not already initialized, then looks up the
+// given key.
+func (l *Lazy) Get(key string) (interface{}, bool, error) {
+ l.init()
+ if l.initErr != nil {
+ return nil, false, l.initErr
+ }
+ v, found := l.cache[key]
+ return v, found, nil
}
// PartitionedLazyCache is a lazily loaded cache paritioned by a supplied string key.
type PartitionedLazyCache struct {
- partitions map[string]*lazyPartition
+ partitions map[string]*Lazy
}
// NewPartitionedLazyCache creates a new NewPartitionedLazyCache with the supplied
// partitions.
func NewPartitionedLazyCache(partitions ...Partition) *PartitionedLazyCache {
- lazyPartitions := make(map[string]*lazyPartition, len(partitions))
+ lazyPartitions := make(map[string]*Lazy, len(partitions))
for _, partition := range partitions {
- lazyPartitions[partition.Key] = &lazyPartition{load: partition.Load}
+ lazyPartitions[partition.Key] = NewLazy(partition.Load)
}
cache := &PartitionedLazyCache{partitions: lazyPartitions}
@@ -67,11 +85,12 @@ func (c *PartitionedLazyCache) Get(partition, key string) (interface{}, error) {
return nil, nil
}
- if err := p.init(); err != nil {
+ v, found, err := p.Get(key)
+ if err != nil {
return nil, err
}
- if v, found := p.cache[key]; found {
+ if found {
return v, nil
}
diff --git a/hugolib/disableKinds_test.go b/hugolib/disableKinds_test.go
index d94307e46..edada1419 100644
--- a/hugolib/disableKinds_test.go
+++ b/hugolib/disableKinds_test.go
@@ -130,7 +130,7 @@ func assertDisabledKinds(th testHelper, s *Site, disabled ...string) {
}, disabled, KindPage, "public/sect/p1/index.html", "Single|P1")
assertDisabledKind(th,
func(isDisabled bool) bool {
- p, _ := s.getPage(nil, "/")
+ p := s.getPage(KindHome)
if isDisabled {
return p == nil
}
@@ -138,7 +138,7 @@ func assertDisabledKinds(th testHelper, s *Site, disabled ...string) {
}, disabled, KindHome, "public/index.html", "Home")
assertDisabledKind(th,
func(isDisabled bool) bool {
- p, _ := s.getPage(nil, "sect")
+ p := s.getPage(KindSection, "sect")
if isDisabled {
return p == nil
}
@@ -146,7 +146,7 @@ func assertDisabledKinds(th testHelper, s *Site, disabled ...string) {
}, disabled, KindSection, "public/sect/index.html", "Sects")
assertDisabledKind(th,
func(isDisabled bool) bool {
- p, _ := s.getPage(nil, "tags/tag1")
+ p := s.getPage(KindTaxonomy, "tags", "tag1")
if isDisabled {
return p == nil
@@ -156,7 +156,7 @@ func assertDisabledKinds(th testHelper, s *Site, disabled ...string) {
}, disabled, KindTaxonomy, "public/tags/tag1/index.html", "Tag1")
assertDisabledKind(th,
func(isDisabled bool) bool {
- p, _ := s.getPage(nil, "tags")
+ p := s.getPage(KindTaxonomyTerm, "tags")
if isDisabled {
return p == nil
}
@@ -165,7 +165,7 @@ func assertDisabledKinds(th testHelper, s *Site, disabled ...string) {
}, disabled, KindTaxonomyTerm, "public/tags/index.html", "Tags")
assertDisabledKind(th,
func(isDisabled bool) bool {
- p, _ := s.getPage(nil, "categories")
+ p := s.getPage(KindTaxonomyTerm, "categories")
if isDisabled {
return p == nil
@@ -175,7 +175,7 @@ func assertDisabledKinds(th testHelper, s *Site, disabled ...string) {
}, disabled, KindTaxonomyTerm, "public/categories/index.html", "Category Terms")
assertDisabledKind(th,
func(isDisabled bool) bool {
- p, _ := s.getPage(nil, "categories/hugo")
+ p := s.getPage(KindTaxonomy, "categories", "hugo")
if isDisabled {
return p == nil
}
diff --git a/hugolib/hugo_sites_build_test.go b/hugolib/hugo_sites_build_test.go
index 34b67be5e..4c32fa2f6 100644
--- a/hugolib/hugo_sites_build_test.go
+++ b/hugolib/hugo_sites_build_test.go
@@ -186,12 +186,12 @@ p1 = "p1en"
assert.Len(sites, 2)
nnSite := sites[0]
- nnHome, _ := nnSite.getPage(nil, "/")
+ nnHome := nnSite.getPage(KindHome)
assert.Len(nnHome.AllTranslations(), 2)
assert.Len(nnHome.Translations(), 1)
assert.True(nnHome.IsTranslated())
- enHome, _ := sites[1].getPage(nil, "/")
+ enHome := sites[1].getPage(KindHome)
p1, err := enHome.Param("p1")
assert.NoError(err)
@@ -242,7 +242,7 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
require.Nil(t, gp2)
enSite := sites[0]
- enSiteHome, _ := enSite.getPage(nil, "/")
+ enSiteHome := enSite.getPage(KindHome)
require.True(t, enSiteHome.IsTranslated())
require.Equal(t, "en", enSite.Language.Lang)
@@ -310,10 +310,10 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
// isn't ideal in a multilingual setup. You want a way to get the current language version if available.
// Now you can do lookups with translation base name to get that behaviour.
// Let us test all the regular page variants:
- getPageDoc1En, _ := enSite.getPage(nil, filepath.ToSlash(doc1en.Path()))
- getPageDoc1EnBase, _ := enSite.getPage(nil, "sect/doc1")
- getPageDoc1Fr, _ := frSite.getPage(nil, filepath.ToSlash(doc1fr.Path()))
- getPageDoc1FrBase, _ := frSite.getPage(nil, "sect/doc1")
+ getPageDoc1En := enSite.getPage(KindPage, filepath.ToSlash(doc1en.Path()))
+ getPageDoc1EnBase := enSite.getPage(KindPage, "sect/doc1")
+ getPageDoc1Fr := frSite.getPage(KindPage, filepath.ToSlash(doc1fr.Path()))
+ getPageDoc1FrBase := frSite.getPage(KindPage, "sect/doc1")
require.Equal(t, doc1en, getPageDoc1En)
require.Equal(t, doc1fr, getPageDoc1Fr)
require.Equal(t, doc1en, getPageDoc1EnBase)
@@ -331,7 +331,7 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
b.AssertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Shortcode: Hello", "LingoDefault")
// Check node translations
- homeEn, _ := enSite.getPage(nil, "/")
+ homeEn := enSite.getPage(KindHome)
require.NotNil(t, homeEn)
require.Len(t, homeEn.Translations(), 3)
require.Equal(t, "fr", homeEn.Translations()[0].Lang())
@@ -341,7 +341,7 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
require.Equal(t, "På bokmål", homeEn.Translations()[2].title, configSuffix)
require.Equal(t, "Bokmål", homeEn.Translations()[2].Language().LanguageName, configSuffix)
- sectFr, _ := frSite.getPage(nil, "sect")
+ sectFr := frSite.getPage(KindSection, "sect")
require.NotNil(t, sectFr)
require.Equal(t, "fr", sectFr.Lang())
@@ -351,12 +351,12 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
nnSite := sites[2]
require.Equal(t, "nn", nnSite.Language.Lang)
- taxNn, _ := nnSite.getPage(nil, "lag")
+ taxNn := nnSite.getPage(KindTaxonomyTerm, "lag")
require.NotNil(t, taxNn)
require.Len(t, taxNn.Translations(), 1)
require.Equal(t, "nb", taxNn.Translations()[0].Lang())
- taxTermNn, _ := nnSite.getPage(nil, "lag/sogndal")
+ taxTermNn := nnSite.getPage(KindTaxonomy, "lag", "sogndal")
require.NotNil(t, taxTermNn)
require.Len(t, taxTermNn.Translations(), 1)
require.Equal(t, "nb", taxTermNn.Translations()[0].Lang())
@@ -411,7 +411,7 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
}
// Check bundles
- bundleFr, _ := frSite.getPage(nil, "bundles/b1/index.md")
+ bundleFr := frSite.getPage(KindPage, "bundles/b1/index.md")
require.NotNil(t, bundleFr)
require.Equal(t, "/blog/fr/bundles/b1/", bundleFr.RelPermalink())
require.Equal(t, 1, len(bundleFr.Resources))
@@ -420,7 +420,7 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
require.Equal(t, "/blog/fr/bundles/b1/logo.png", logoFr.RelPermalink())
b.AssertFileContent("public/fr/bundles/b1/logo.png", "PNG Data")
- bundleEn, _ := enSite.getPage(nil, "bundles/b1/index.en.md")
+ bundleEn := enSite.getPage(KindPage, "bundles/b1/index.en.md")
require.NotNil(t, bundleEn)
require.Equal(t, "/blog/en/bundles/b1/", bundleEn.RelPermalink())
require.Equal(t, 1, len(bundleEn.Resources))
@@ -582,7 +582,7 @@ func TestMultiSitesRebuild(t *testing.T) {
docFr := readDestination(t, fs, "public/fr/sect/doc1/index.html")
require.True(t, strings.Contains(docFr, "Salut"), "No Salut")
- homeEn, _ := enSite.getPage(nil, "/")
+ homeEn := enSite.getPage(KindHome)
require.NotNil(t, homeEn)
assert.Len(homeEn.Translations(), 3)
require.Equal(t, "fr", homeEn.Translations()[0].Lang())
@@ -678,7 +678,7 @@ title = "Svenska"
require.True(t, svSite.Language.Lang == "sv", svSite.Language.Lang)
require.True(t, frSite.Language.Lang == "fr", frSite.Language.Lang)
- homeEn, _ := enSite.getPage(nil, "/")
+ homeEn := enSite.getPage(KindHome)
require.NotNil(t, homeEn)
require.Len(t, homeEn.Translations(), 4)
require.Equal(t, "sv", homeEn.Translations()[0].Lang())
diff --git a/hugolib/hugo_sites_multihost_test.go b/hugolib/hugo_sites_multihost_test.go
index 736c6d4f0..4062868e6 100644
--- a/hugolib/hugo_sites_multihost_test.go
+++ b/hugolib/hugo_sites_multihost_test.go
@@ -55,7 +55,7 @@ languageName = "Nynorsk"
s1 := b.H.Sites[0]
- s1h, _ := s1.getPage(nil, "/")
+ s1h := s1.getPage(KindHome)
assert.True(s1h.IsTranslated())
assert.Len(s1h.Translations(), 2)
assert.Equal("https://example.com/docs/", s1h.Permalink())
@@ -66,7 +66,7 @@ languageName = "Nynorsk"
// For multihost, we never want any content in the root.
//
// check url in front matter:
- pageWithURLInFrontMatter, _ := s1.getPage(nil, "sect/doc3.en.md")
+ pageWithURLInFrontMatter := s1.getPage(KindPage, "sect/doc3.en.md")
assert.NotNil(pageWithURLInFrontMatter)
assert.Equal("/superbob", pageWithURLInFrontMatter.URL())
assert.Equal("/docs/superbob/", pageWithURLInFrontMatter.RelPermalink())
@@ -78,7 +78,7 @@ languageName = "Nynorsk"
s2 := b.H.Sites[1]
- s2h, _ := s2.getPage(nil, "/")
+ s2h := s2.getPage(KindHome)
assert.Equal("https://example.fr/", s2h.Permalink())
b.AssertFileContent("public/fr/index.html", "French Home Page")
@@ -92,7 +92,7 @@ languageName = "Nynorsk"
// Check bundles
- bundleEn, _ := s1.getPage(nil, "bundles/b1/index.en.md")
+ bundleEn := s1.getPage(KindPage, "bundles/b1/index.en.md")
require.NotNil(t, bundleEn)
require.Equal(t, "/docs/bundles/b1/", bundleEn.RelPermalink())
require.Equal(t, 1, len(bundleEn.Resources))
@@ -101,7 +101,7 @@ languageName = "Nynorsk"
require.Equal(t, "/docs/bundles/b1/logo.png", logoEn.RelPermalink())
b.AssertFileContent("public/en/bundles/b1/logo.png", "PNG Data")
- bundleFr, _ := s2.getPage(nil, "bundles/b1/index.md")
+ bundleFr := s2.getPage(KindPage, "bundles/b1/index.md")
require.NotNil(t, bundleFr)
require.Equal(t, "/bundles/b1/", bundleFr.RelPermalink())
require.Equal(t, 1, len(bundleFr.Resources))
diff --git a/hugolib/language_content_dir_test.go b/hugolib/language_content_dir_test.go
index 73119d3db..3c3642bf3 100644
--- a/hugolib/language_content_dir_test.go
+++ b/hugolib/language_content_dir_test.go
@@ -207,6 +207,29 @@ Content.
assert.Equal(10, len(svSite.RegularPages))
+ svP2, err := svSite.getPageNew(nil, "/sect/page2.md")
+ assert.NoError(err)
+ nnP2, err := nnSite.getPageNew(nil, "/sect/page2.md")
+ assert.NoError(err)
+ nnP2_2, err := svSite.getPageNew(nil, "/nn/sect/page2.md")
+ assert.NoError(err)
+ enP2_2, err := nnSite.getPageNew(nil, "/en/sect/page2.md")
+ assert.NoError(err)
+ svP2_2, err := enSite.getPageNew(nil, "/sv/sect/page2.md")
+ assert.NoError(err)
+
+ enP2, err := enSite.getPageNew(nil, "/sect/page2.md")
+ assert.NoError(err)
+ assert.NotNil(enP2)
+ assert.NotNil(svP2)
+ assert.NotNil(nnP2)
+ assert.Equal("sv", svP2.Lang())
+ assert.Equal("nn", nnP2.Lang())
+ assert.Equal("en", enP2.Lang())
+ assert.Equal(nnP2, nnP2_2)
+ assert.Equal(enP2, enP2_2)
+ assert.Equal(svP2, svP2_2)
+
for i, p := range enSite.RegularPages {
j := i + 1
msg := fmt.Sprintf("Test %d", j)
@@ -244,7 +267,7 @@ Content.
b.AssertFileContent("/my/project/public/sv/sect/mybundle/logo.png", "PNG Data")
b.AssertFileContent("/my/project/public/nn/sect/mybundle/logo.png", "PNG Data")
- nnSect, _ := nnSite.getPage(nil, "sect")
+ nnSect := nnSite.getPage(KindSection, "sect")
assert.NotNil(nnSect)
assert.Equal(12, len(nnSect.Pages))
nnHome, _ := nnSite.Info.Home()
diff --git a/hugolib/page.go b/hugolib/page.go
index 710bca3f1..0b820b779 100644
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -1875,24 +1875,24 @@ func (p *Page) FullFilePath() string {
}
// Returns the canonical, absolute fully-qualifed logical reference used by
-// methods such as GetPage and ref/relref shortcodes to unambiguously refer to
-// this page. As an absolute path, it is prefixed with a "/".
+// methods such as GetPage and ref/relref shortcodes to refer to
+// this page. It is prefixed with a "/".
//
-// For pages that have a backing file in the content directory, it is returns
-// the path to this file as an absolute path rooted in the content dir. For
-// pages or nodes that do not, it returns the virtual path, consistent with
-// where you would add a backing content file.
-//
-// The "/" prefix and support for pages without backing files should be the
-// only difference with FullFilePath()
+// For pages that have a source file, it is returns the path to this file as an
+// absolute path rooted in this site's content dir.
+// For pages that do not (sections witout content page etc.), it returns the
+// virtual path, consistent with where you would add a source file.
func (p *Page) absoluteSourceRef() string {
sourcePath := p.Source.Path()
if sourcePath != "" {
return "/" + filepath.ToSlash(sourcePath)
- } else if len(p.sections) > 0 {
+ }
+
+ if len(p.sections) > 0 {
// no backing file, return the virtual source path
return "/" + path.Join(p.sections...)
}
+
return ""
}
@@ -2035,7 +2035,7 @@ func (p *Page) Hugo() *HugoInfo {
// This will return nil when no page could be found, and will return
// an error if the ref is ambiguous.
func (p *Page) GetPage(ref string) (*Page, error) {
- return p.s.getPage(p, ref)
+ return p.s.getPageNew(p, ref)
}
func (p *Page) Ref(refs ...string) (string, error) {
@@ -2059,8 +2059,8 @@ func (p *Page) RelRef(refs ...string) (string, error) {
}
func (p *Page) String() string {
- if p.absoluteSourceRef() != "" {
- return fmt.Sprintf("Page(%s)", p.absoluteSourceRef())
+ if sourceRef := p.absoluteSourceRef(); sourceRef != "" {
+ return fmt.Sprintf("Page(%s)", sourceRef)
}
return fmt.Sprintf("Page(%q)", p.title)
}
diff --git a/hugolib/page_bundler_test.go b/hugolib/page_bundler_test.go
index f12b7d24f..811dbf56f 100644
--- a/hugolib/page_bundler_test.go
+++ b/hugolib/page_bundler_test.go
@@ -48,7 +48,6 @@ func TestPageBundlerSiteRegular(t *testing.T) {
for _, ugly := range []bool{false, true} {
t.Run(fmt.Sprintf("ugly=%t", ugly),
func(t *testing.T) {
- var samePage *Page
assert := require.New(t)
fs, cfg := newTestBundleSources(t)
@@ -84,14 +83,12 @@ func TestPageBundlerSiteRegular(t *testing.T) {
assert.Len(s.RegularPages, 8)
- singlePage, _ := s.getPage(nil, "a/1.md")
+ singlePage := s.getPage(KindPage, "a/1.md")
assert.Equal("", singlePage.BundleType())
assert.NotNil(singlePage)
- samePage, _ = s.getPage(nil, "a/1")
- assert.Equal(singlePage, samePage)
- samePage, _ = s.getPage(nil, "1")
- assert.Equal(singlePage, samePage)
+ assert.Equal(singlePage, s.getPage("page", "a/1"))
+ assert.Equal(singlePage, s.getPage("page", "1"))
assert.Contains(singlePage.content(), "TheContent")
@@ -109,18 +106,18 @@ func TestPageBundlerSiteRegular(t *testing.T) {
// This should be just copied to destination.
th.assertFileContent(filepath.FromSlash("/work/public/assets/pic1.png"), "content")
- leafBundle1, _ := s.getPage(nil, "b/my-bundle/index.md")
+ leafBundle1 := s.getPage(KindPage, "b/my-bundle/index.md")
assert.NotNil(leafBundle1)
assert.Equal("leaf", leafBundle1.BundleType())
assert.Equal("b", leafBundle1.Section())
- sectionB, _ := s.getPage(nil, "/b")
+ sectionB := s.getPage(KindSection, "b")
assert.NotNil(sectionB)
home, _ := s.Info.Home()
assert.Equal("branch", home.BundleType())
// This is a root bundle and should live in the "home section"
// See https://github.com/gohugoio/hugo/issues/4332
- rootBundle, _ := s.getPage(nil, "root")
+ rootBundle := s.getPage(KindPage, "root")
assert.NotNil(rootBundle)
assert.True(rootBundle.Parent().IsHome())
if ugly {
@@ -129,9 +126,9 @@ func TestPageBundlerSiteRegular(t *testing.T) {
assert.Equal("/root/", rootBundle.RelPermalink())
}
- leafBundle2, _ := s.getPage(nil, "a/b/index.md")
+ leafBundle2 := s.getPage(KindPage, "a/b/index.md")
assert.NotNil(leafBundle2)
- unicodeBundle, _ := s.getPage(nil, "c/bundle/index.md")
+ unicodeBundle := s.getPage(KindPage, "c/bundle/index.md")
assert.NotNil(unicodeBundle)
pageResources := leafBundle1.Resources.ByType(pageResourceType)
@@ -214,7 +211,6 @@ func TestPageBundlerSiteMultilingual(t *testing.T) {
for _, ugly := range []bool{false, true} {
t.Run(fmt.Sprintf("ugly=%t", ugly),
func(t *testing.T) {
- var samePage *Page
assert := require.New(t)
fs, cfg := newTestBundleSourcesMultilingual(t)
@@ -234,7 +230,7 @@ func TestPageBundlerSiteMultilingual(t *testing.T) {
assert.Equal(16, len(s.Pages))
assert.Equal(31, len(s.AllPages))
- bundleWithSubPath, _ := s.getPage(nil, "lb/index")
+ bundleWithSubPath := s.getPage(KindPage, "lb/index")
assert.NotNil(bundleWithSubPath)
// See https://github.com/gohugoio/hugo/issues/4312
@@ -248,28 +244,22 @@ func TestPageBundlerSiteMultilingual(t *testing.T) {
// and probably also just b (aka "my-bundle")
// These may also be translated, so we also need to test that.
// "bf", "my-bf-bundle", "index.md + nn
- bfBundle, _ := s.getPage(nil, "bf/my-bf-bundle/index")
+ bfBundle := s.getPage(KindPage, "bf/my-bf-bundle/index")
assert.NotNil(bfBundle)
assert.Equal("en", bfBundle.Lang())
- samePage, _ = s.getPage(nil, "bf/my-bf-bundle/index.md")
- assert.Equal(bfBundle, samePage)
- samePage, _ = s.getPage(nil, "bf/my-bf-bundle")
- assert.Equal(bfBundle, samePage)
- samePage, _ = s.getPage(nil, "my-bf-bundle")
- assert.Equal(bfBundle, samePage)
+ assert.Equal(bfBundle, s.getPage(KindPage, "bf/my-bf-bundle/index.md"))
+ assert.Equal(bfBundle, s.getPage(KindPage, "bf/my-bf-bundle"))
+ assert.Equal(bfBundle, s.getPage(KindPage, "my-bf-bundle"))
nnSite := sites.Sites[1]
assert.Equal(7, len(nnSite.RegularPages))
- bfBundleNN, _ := nnSite.getPage(nil, "bf/my-bf-bundle/index")
+ bfBundleNN := nnSite.getPage(KindPage, "bf/my-bf-bundle/index")
assert.NotNil(bfBundleNN)
assert.Equal("nn", bfBundleNN.Lang())
- samePage, _ = nnSite.getPage(nil, "bf/my-bf-bundle/index.nn.md")
- assert.Equal(bfBundleNN, samePage)
- samePage, _ = nnSite.getPage(nil, "bf/my-bf-bundle")
- assert.Equal(bfBundleNN, samePage)
- samePage, _ = nnSite.getPage(nil, "my-bf-bundle")
- assert.Equal(bfBundleNN, samePage)
+ assert.Equal(bfBundleNN, nnSite.getPage(KindPage, "bf/my-bf-bundle/index.nn.md"))
+ assert.Equal(bfBundleNN, nnSite.getPage(KindPage, "bf/my-bf-bundle"))
+ assert.Equal(bfBundleNN, nnSite.getPage(KindPage, "my-bf-bundle"))
// See https://github.com/gohugoio/hugo/issues/4295
// Every resource should have its Name prefixed with its base folder.
@@ -344,7 +334,7 @@ func TestPageBundlerSiteWitSymbolicLinksInContent(t *testing.T) {
th := testHelper{s.Cfg, s.Fs, t}
assert.Equal(7, len(s.RegularPages))
- a1Bundle, _ := s.getPage(nil, "symbolic2/a1/index.md")
+ a1Bundle := s.getPage(KindPage, "symbolic2/a1/index.md")
assert.NotNil(a1Bundle)
assert.Equal(2, len(a1Bundle.Resources))
assert.Equal(1, len(a1Bundle.Resources.ByType(pageResourceType)))
@@ -404,10 +394,10 @@ HEADLESS {{< myShort >}}
assert.Equal(1, len(s.RegularPages))
assert.Equal(1, len(s.headlessPages))
- regular, _ := s.getPage(nil, "a/index")
+ regular := s.getPage(KindPage, "a/index")
assert.Equal("/a/s1/", regular.RelPermalink())
- headless, _ := s.getPage(nil, "b/index")
+ headless := s.getPage(KindPage, "b/index")
assert.NotNil(headless)
assert.True(headless.headless)
assert.Equal("Headless Bundle in Topless Bar", headless.Title())
diff --git a/hugolib/page_collections.go b/hugolib/page_collections.go
index df93b6f9f..7ec03c1f1 100644
--- a/hugolib/page_collections.go
+++ b/hugolib/page_collections.go
@@ -16,11 +16,9 @@ package hugolib
import (
"fmt"
"path"
- "path/filepath"
"strings"
- "sync"
- "github.com/gohugoio/hugo/helpers"
+ "github.com/gohugoio/hugo/cache"
)
// PageCollections contains the page collections for a site.
@@ -49,29 +47,29 @@ type PageCollections struct {
// Includes headless bundles, i.e. bundles that produce no output for its content page.
headlessPages Pages
- pageIndex
-}
-
-type pageIndex struct {
- initSync sync.Once
- index map[string]*Page
- load func() map[string]*Page
-}
-
-func (pi *pageIndex) init() {
- pi.initSync.Do(func() {
- pi.index = pi.load()
- })
+ pageIndex *cache.Lazy
}
// Get initializes the index if not already done so, then
// looks up the given page ref, returns nil if no value found.
-func (pi *pageIndex) Get(ref string) *Page {
- pi.init()
- return pi.index[ref]
+func (c *PageCollections) getFromCache(ref string) (*Page, error) {
+ v, found, err := c.pageIndex.Get(ref)
+ if err != nil {
+ return nil, err
+ }
+ if !found {
+ return nil, nil
+ }
+
+ p := v.(*Page)
+
+ if p != ambiguityFlag {
+ return p, nil
+ }
+ return nil, fmt.Errorf("page reference %q is ambiguous", ref)
}
-var ambiguityFlag = &Page{Kind: "dummy", title: "ambiguity flag"}
+var ambiguityFlag = &Page{Kind: kindUnknown, title: "ambiguity flag"}
func (c *PageCollections) refreshPageCaches() {
c.indexPages = c.findPagesByKindNotIn(KindPage, c.Pages)
@@ -84,46 +82,55 @@ func (c *PageCollections) refreshPageCaches() {
s = c.Pages[0].s
}
- indexLoader := func() map[string]*Page {
- index := make(map[string]*Page)
+ indexLoader := func() (map[string]interface{}, error) {
+ index := make(map[string]interface{})
+
+ add := func(ref string, p *Page) {
+ existing := index[ref]
+ if existing == nil {
+ index[ref] = p
+ } else if existing != ambiguityFlag && existing != p {
+ index[ref] = ambiguityFlag
+ }
+ }
// Note that we deliberately use the pages from all sites
// in this index, as we intend to use this in the ref and relref
- // shortcodes. If the user says "sect/doc1.en.md", he/she knows
- // what he/she is looking for.
+ // shortcodes.
for _, pageCollection := range []Pages{c.AllRegularPages, c.headlessPages} {
for _, p := range pageCollection {
-
sourceRef := p.absoluteSourceRef()
- if sourceRef != "" {
- // index the canonical, unambiguous ref
- // e.g. /section/article.md
- indexPage(index, sourceRef, p)
-
- // also index the legacy canonical lookup (not guaranteed to be unambiguous)
- // e.g. section/article.md
- indexPage(index, sourceRef[1:], p)
- }
+ // Allow cross language references by
+ // adding the language code as prefix.
+ add(path.Join("/"+p.Lang(), sourceRef), p)
+
+ // For pages in the current language.
if s != nil && p.s == s {
+ if sourceRef != "" {
+ // index the canonical ref
+ // e.g. /section/article.md
+ add(sourceRef, p)
+ }
+
// Ref/Relref supports this potentially ambiguous lookup.
- indexPage(index, p.Source.LogicalName(), p)
+ add(p.Source.LogicalName(), p)
translationBaseName := p.Source.TranslationBaseName()
- dir := filepath.ToSlash(strings.TrimSuffix(p.Dir(), helpers.FilePathSeparator))
+
+ dir, _ := path.Split(sourceRef)
+ dir = strings.TrimSuffix(dir, "/")
if translationBaseName == "index" {
- _, name := path.Split(dir)
- indexPage(index, name, p)
- indexPage(index, dir, p)
+ add(dir, p)
+ add(path.Base(dir), p)
} else {
- // Again, ambiguous
- indexPage(index, translationBaseName, p)
+ add(translationBaseName, p)
}
// We need a way to get to the current language version.