diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2018-07-17 11:18:29 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2018-07-18 00:07:20 +0200 |
commit | 3eb313fef495a39731dafa6bddbf77760090230d (patch) | |
tree | aa93e04123fa299e27b4d701b81d7976865d299c | |
parent | b93417aa1d3d38a9e56bad25937e0e638a113faf (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.go | 41 | ||||
-rw-r--r-- | hugolib/disableKinds_test.go | 12 | ||||
-rw-r--r-- | hugolib/hugo_sites_build_test.go | 30 | ||||
-rw-r--r-- | hugolib/hugo_sites_multihost_test.go | 10 | ||||
-rw-r--r-- | hugolib/language_content_dir_test.go | 25 | ||||
-rw-r--r-- | hugolib/page.go | 26 | ||||
-rw-r--r-- | hugolib/page_bundler_test.go | 50 | ||||
-rw-r--r-- | hugolib/page_collections.go | 171 | ||||
-rw-r--r-- | hugolib/page_collections_test.go | 15 | ||||
-rw-r--r-- | hugolib/pages_language_merge_test.go | 4 | ||||
-rw-r--r-- | hugolib/shortcode_test.go | 2 | ||||
-rw-r--r-- | hugolib/site.go | 47 | ||||
-rw-r--r-- | hugolib/site_output_test.go | 4 | ||||
-rw-r--r-- | hugolib/site_sections_test.go | 31 | ||||
-rw-r--r-- | hugolib/site_test.go | 19 | ||||
-rw-r--r-- | hugolib/site_url_test.go | 6 | ||||
-rw-r--r-- | hugolib/taxonomy_test.go | 12 |
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. |