diff options
-rw-r--r-- | helpers/path.go | 9 | ||||
-rw-r--r-- | htesting/hqt/checkers.go | 2 | ||||
-rw-r--r-- | hugolib/content_map.go | 161 | ||||
-rw-r--r-- | hugolib/content_map_page.go | 69 | ||||
-rw-r--r-- | hugolib/content_map_test.go | 86 | ||||
-rw-r--r-- | hugolib/page.go | 19 | ||||
-rw-r--r-- | hugolib/page__tree.go | 6 | ||||
-rw-r--r-- | hugolib/pagecollections.go | 14 | ||||
-rw-r--r-- | hugolib/pagecollections_test.go | 6 | ||||
-rw-r--r-- | hugolib/taxonomy_test.go | 1 |
10 files changed, 211 insertions, 162 deletions
diff --git a/helpers/path.go b/helpers/path.go index 29e1e6071..01c452607 100644 --- a/helpers/path.go +++ b/helpers/path.go @@ -665,3 +665,12 @@ func FileContainsAny(filename string, subslices [][]byte, fs afero.Fs) (bool, er func Exists(path string, fs afero.Fs) (bool, error) { return afero.Exists(fs, path) } + +// AddTrailingSlash adds a trailing Unix styled slash (/) if not already +// there. +func AddTrailingSlash(path string) string { + if !strings.HasSuffix(path, "/") { + path += "/" + } + return path +} diff --git a/htesting/hqt/checkers.go b/htesting/hqt/checkers.go index 6fb65ee47..c12f78034 100644 --- a/htesting/hqt/checkers.go +++ b/htesting/hqt/checkers.go @@ -77,7 +77,7 @@ func (c *stringChecker) Check(got interface{}, args []interface{}, note func(key return nil } - return fmt.Errorf("values are not the same text: %s", htesting.DiffStrings(s1, s2)) + return fmt.Errorf("values are not the same text: %s", strings.Join(htesting.DiffStrings(s1, s2), " | ")) } func normalizeString(s string) string { diff --git a/hugolib/content_map.go b/hugolib/content_map.go index 3c57fffcf..ddcc70707 100644 --- a/hugolib/content_map.go +++ b/hugolib/content_map.go @@ -20,6 +20,8 @@ import ( "strings" "sync" + "github.com/gohugoio/hugo/helpers" + "github.com/gohugoio/hugo/resources/page" "github.com/pkg/errors" @@ -31,27 +33,26 @@ import ( ) // We store the branch nodes in either the `sections` or `taxonomies` tree -// with their path as a key; Unix style slashes, a leading slash but no -// trailing slash. +// with their path as a key; Unix style slashes, a leading and trailing slash. // -// E.g. "/blog" or "/categories/funny" +// E.g. "/blog/" or "/categories/funny/" // // Pages that belongs to a section are stored in the `pages` tree below -// the section name and a branch separator, e.g. "/blog__hb_". A page is +// the section name and a branch separator, e.g. "/blog/__hb_". A page is // given a key using the path below the section and the base filename with no extension // with a leaf separator added. // // For bundled pages (/mybundle/index.md), we use the folder name. // -// An exmple of a full page key would be "/blog__hb_/page1__hl_" +// An exmple of a full page key would be "/blog/__hb_page1__hl_" // // Bundled resources are stored in the `resources` having their path prefixed // with the bundle they belong to, e.g. -// "/blog__hb_/bundle__hl_data.json". +// "/blog/__hb_bundle__hl_data.json". // // The weighted taxonomy entries extracted from page front matter are stored in // the `taxonomyEntries` tree below /plural/term/page-key, e.g. -// "/categories/funny/blog__hb_/bundle__hl_". +// "/categories/funny/blog/__hb_bundle__hl_". const ( cmBranchSeparator = "__hb_" cmLeafSeparator = "__hl_" @@ -105,7 +106,7 @@ func newContentMap(cfg contentMapConfig) *contentMap { addToReverseMap(mountKey, n, m) } } - k := strings.TrimSuffix(path.Base(s), cmLeafSeparator) + k := strings.TrimPrefix(strings.TrimSuffix(path.Base(s), cmLeafSeparator), cmBranchSeparator) addToReverseMap(k, n, m) return false }) @@ -127,18 +128,15 @@ type cmInsertKeyBuilder struct { } func (b cmInsertKeyBuilder) ForPage(s string) *cmInsertKeyBuilder { - // TODO2 fmt.Println("ForPage:", s, "baseKey:", b.baseKey, "key:", b.key) + //fmt.Println("ForPage:", s, "baseKey:", b.baseKey, "key:", b.key) baseKey := b.baseKey b.baseKey = s - if !strings.HasPrefix(s, "/") { - s = "/" + s - } - if baseKey != "/" { // Don't repeat the section path in the key. s = strings.TrimPrefix(s, baseKey) } + s = strings.TrimPrefix(s, "/") switch b.tree { case b.m.sections: @@ -154,10 +152,10 @@ func (b cmInsertKeyBuilder) ForPage(s string) *cmInsertKeyBuilder { } func (b cmInsertKeyBuilder) ForResource(s string) *cmInsertKeyBuilder { - // TODO2 fmt.Println("ForResource:", s, "baseKey:", b.baseKey, "key:", b.key) + //fmt.Println("ForResource:", s, "baseKey:", b.baseKey, "key:", b.key) - s = strings.TrimPrefix(s, "/") - s = strings.TrimPrefix(s, strings.TrimPrefix(b.baseKey, "/")+"/") + baseKey := helpers.AddTrailingSlash(b.baseKey) + s = strings.TrimPrefix(s, baseKey) switch b.tree { case b.m.pages: @@ -173,14 +171,23 @@ func (b cmInsertKeyBuilder) ForResource(s string) *cmInsertKeyBuilder { func (b *cmInsertKeyBuilder) Insert(n *contentNode) *cmInsertKeyBuilder { if b.err == nil { - b.tree.Insert(cleanTreeKey(b.key), n) + b.tree.Insert(b.Key(), n) } return b } +func (b *cmInsertKeyBuilder) Key() string { + switch b.tree { + case b.m.sections, b.m.taxonomies: + return cleanSectionTreeKey(b.key) + default: + return cleanTreeKey(b.key) + } +} + func (b *cmInsertKeyBuilder) DeleteAll() *cmInsertKeyBuilder { if b.err == nil { - b.tree.DeletePrefix(cleanTreeKey(b.key)) + b.tree.DeletePrefix(b.Key()) } return b } @@ -211,15 +218,16 @@ func (b *cmInsertKeyBuilder) WithFile(fi hugofs.FileMetaInfo) *cmInsertKeyBuilde } func (b *cmInsertKeyBuilder) WithSection(s string) *cmInsertKeyBuilder { + s = cleanSectionTreeKey(s) b.newTopLevel() b.tree = b.m.sections b.baseKey = s b.key = s - // TODO2 fmt.Println("WithSection:", s, "baseKey:", b.baseKey, "key:", b.key) return b } func (b *cmInsertKeyBuilder) WithTaxonomy(s string) *cmInsertKeyBuilder { + s = cleanSectionTreeKey(s) b.newTopLevel() b.tree = b.m.taxonomies b.baseKey = s @@ -233,20 +241,17 @@ func (b *cmInsertKeyBuilder) getBundle(s string) (string, string) { m := b.m section, _ := m.getSection(s) - p := s - if section != "/" { - p = strings.TrimPrefix(s, section) - } + p := strings.TrimPrefix(s, section) - bundlePathParts := strings.Split(p, "/")[1:] + bundlePathParts := strings.Split(p, "/") basePath := section + cmBranchSeparator // Put it into an existing bundle if found. for i := len(bundlePathParts) - 2; i >= 0; i-- { bundlePath := path.Join(bundlePathParts[:i]...) - searchKey := basePath + "/" + bundlePath + cmLeafSeparator + searchKey := basePath + bundlePath + cmLeafSeparator if _, found := m.pages.Get(searchKey); found { - return section + "/" + bundlePath, searchKey + return section + bundlePath, searchKey } } @@ -432,7 +437,7 @@ func (m *contentMap) CreateMissingNodes() error { sectionPath = sectionPath[:firstSlash] } } - sect = cleanTreeKey(sect) + sect = cleanSectionTreeKey(sect) _, found := m.sections.Get(sect) if !found { m.sections.Insert(sect, &contentNode{path: sectionPath}) @@ -440,7 +445,7 @@ func (m *contentMap) CreateMissingNodes() error { } for _, view := range m.cfg.taxonomyConfig { - s := cleanTreeKey(view.plural) + s := cleanSectionTreeKey(view.plural) _, found := m.taxonomies.Get(s) if !found { b := &contentNode{ @@ -476,15 +481,20 @@ func (m *contentMap) newContentNodeFromFi(fi hugofs.FileMetaInfo) *contentNode { } func (m *contentMap) getFirstSection(s string) (string, *contentNode) { + s = helpers.AddTrailingSlash(s) for { k, v, found := m.sections.LongestPrefix(s) + if !found { return "", nil } - if strings.Count(k, "/") == 1 { + + if strings.Count(k, "/") <= 2 { return k, v.(*contentNode) } - s = path.Dir(s) + + s = helpers.AddTrailingSlash(path.Dir(strings.TrimSuffix(s, "/"))) + } } @@ -507,10 +517,7 @@ func (m *contentMap) getOrCreateSection(n *contentNode, s string) (string, *cont } if mustCreate { - k = s[:strings.Index(s[1:], "/")+1] - if k == "" { - k = "/" - } + k = cleanSectionTreeKey(s[:strings.Index(s[1:], "/")+1]) b = &contentNode{ path: n.rootSection(), @@ -523,7 +530,9 @@ func (m *contentMap) getOrCreateSection(n *contentNode, s string) (string, *cont } func (m *contentMap) getPage(section, name string) *contentNode { - key := section + cmBranchSeparator + "/" + name + cmLeafSeparator + section = helpers.AddTrailingSlash(section) + key := section + cmBranchSeparator + name + cmLeafSeparator + v, found := m.pages.Get(key) if found { return v.(*contentNode) @@ -532,7 +541,9 @@ func (m *contentMap) getPage(section, name string) *contentNode { } func (m *contentMap) getSection(s string) (string, *contentNode) { - k, v, found := m.sections.LongestPrefix(path.Dir(s)) + s = helpers.AddTrailingSlash(path.Dir(strings.TrimSuffix(s, "/"))) + + k, v, found := m.sections.LongestPrefix(s) if found { return k, v.(*contentNode) @@ -541,21 +552,18 @@ func (m *contentMap) getSection(s string) (string, *contentNode) { } func (m *contentMap) getTaxonomyParent(s string) (string, *contentNode) { - s = path.Dir(s) - if s == "/" { - v, found := m.sections.Get(s) - if found { - return s, v.(*contentNode) - } - return "", nil + s = helpers.AddTrailingSlash(path.Dir(strings.TrimSuffix(s, "/"))) + k, v, found := m.taxonomies.LongestPrefix(s) + + if found { + return k, v.(*contentNode) } - for _, tree := range []*contentTree{m.taxonomies, m.sections} { - k, v, found := tree.LongestPrefix(s) - if found { - return k, v.(*contentNode) - } + v, found = m.sections.Get("/") + if found { + return s, v.(*contentNode) } + return "", nil } @@ -569,6 +577,15 @@ func cleanTreeKey(k string) string { return k } +func cleanSectionTreeKey(k string) string { + k = cleanTreeKey(k) + if k != "/" { + k += "/" + } + + return k +} + func (m *contentMap) onSameLevel(s1, s2 string) bool { return strings.Count(s1, "/") == strings.Count(s2, "/") } @@ -606,13 +623,13 @@ func (m *contentMap) deleteOrphanSections() { return false } - if s == "/" || strings.Count(s, "/") > 1 { + if s == "/" || strings.Count(s, "/") > 2 { return false } prefixBundle := s + cmBranchSeparator - if !(m.sections.hasPrefix(s+"/") || m.pages.hasPrefix(prefixBundle) || m.resources.hasPrefix(prefixBundle)) { + if !(m.sections.hasBelow(s) || m.pages.hasBelow(prefixBundle) || m.resources.hasBelow(prefixBundle)) { sectionsToDelete = append(sectionsToDelete, s) } @@ -630,13 +647,15 @@ func (m *contentMap) deletePage(s string) { } func (m *contentMap) deleteSectionByPath(s string) { - m.sections.Delete(s) - m.sections.DeletePrefix(s + "/") - m.pages.DeletePrefix(s + cmBranchSeparator) - m.pages.DeletePrefix(s + "/") - m.resources.DeletePrefix(s + cmBranchSeparator) - m.resources.DeletePrefix(s + cmLeafSeparator) - m.resources.DeletePrefix(s + "/") + if !strings.HasSuffix(s, "/") { + panic("section must end with a slash") + } + if !strings.HasPrefix(s, "/") { + panic("section must start with a slash") + } + m.sections.DeletePrefix(s) + m.pages.DeletePrefix(s) + m.resources.DeletePrefix(s) } func (m *contentMap) deletePageByPath(s string) { @@ -648,8 +667,7 @@ func (m *contentMap) deletePageByPath(s string) { } func (m *contentMap) deleteTaxonomy(s string) { - m.taxonomies.Delete(s) - m.taxonomies.DeletePrefix(s + "/") + m.taxonomies.DeletePrefix(s) } func (m *contentMap) reduceKeyPart(dir, filename string) string { @@ -817,7 +835,7 @@ func (c *contentTree) WalkQuery(query pageMapQuery, walkFn contentTreeNodeCallba filter = contentTreeNoListAlwaysFilter } if query.Prefix != "" { - c.WalkPrefix(query.Prefix, func(s string, v interface{}) bool { + c.WalkBelow(query.Prefix, func(s string, v interface{}) bool { n := v.(*contentNode) if filter != nil && filter(s, n) { return false @@ -862,6 +880,18 @@ func (c contentTrees) WalkPrefix(prefix string, fn contentTreeNodeCallback) { } } +// WalkBelow walks the tree below the given prefix, i.e. it skips the +// node with the given prefix as key. +func (c *contentTree) WalkBelow(prefix string, fn radix.WalkFn) { + c.Tree.WalkPrefix(prefix, func(s string, v interface{}) bool { + if s == prefix { + return false + } + return fn(s, v) + }) + +} + func (c *contentTree) getMatch(matches func(b *contentNode) bool) string { var match string c.Walk(func(s string, v interface{}) bool { @@ -881,9 +911,9 @@ func (c *contentTree) getMatch(matches func(b *contentNode) bool) string { return match } -func (c *contentTree) hasPrefix(s string) bool { +func (c *contentTree) hasBelow(s1 string) bool { var t bool - c.Tree.WalkPrefix(s, func(s string, v interface{}) bool { + c.WalkBelow(s1, func(s2 string, v interface{}) bool { t = true return true }) @@ -953,12 +983,7 @@ func (c *contentTreeRef) getPagesRecursive() page.Pages { Filter: c.n.p.m.getListFilter(true), } - query.Prefix = c.key + cmBranchSeparator - c.m.collectPages(query, func(c *contentNode) { - pas = append(pas, c.p) - }) - - query.Prefix = c.key + "/" + query.Prefix = c.key c.m.collectPages(query, func(c *contentNode) { pas = append(pas, c.p) }) diff --git a/hugolib/content_map_page.go b/hugolib/content_map_page.go index 6be56f3f5..7516a7029 100644 --- a/hugolib/content_map_page.go +++ b/hugolib/content_map_page.go @@ -70,7 +70,7 @@ func (m *pageMap) createMissingTaxonomyNodes() error { m.taxonomyEntries.Walk(func(s string, v interface{}) bool { n := v.(*contentNode) vi := n.viewInfo - k := cleanTreeKey(vi.name.plural + "/" + vi.termKey) + k := cleanSectionTreeKey(vi.name.plural + "/" + vi.termKey) if _, found := m.taxonomies.Get(k); !found { vic := &contentBundleViewInfo{ @@ -266,6 +266,7 @@ func (m *pageMap) newResource(fim hugofs.FileMetaInfo, owner *pageState) (resour func (m *pageMap) createSiteTaxonomies() error { m.s.taxonomies = make(TaxonomyList) + var walkErr error m.taxonomies.Walk(func(s string, v interface{}) bool { n := v.(*contentNode) t := n.viewInfo @@ -276,7 +277,11 @@ func (m *pageMap) createSiteTaxonomies() error { m.s.taxonomies[viewName.plural] = make(Taxonomy) } else { taxonomy := m.s.taxonomies[viewName.plural] - m.taxonomyEntries.WalkPrefix(s+"/", func(ss string, v interface{}) bool { + if taxonomy == nil { + walkErr = errors.Errorf("missing taxonomy: %s", viewName.plural) + return true + } + m.taxonomyEntries.WalkPrefix(s, func(ss string, v interface{}) bool { b2 := v.(*contentNode) info := b2.viewInfo taxonomy.add(info.termKey, page.NewWeightedPage(info.weight, info.ref.p, n.p)) @@ -294,7 +299,7 @@ func (m *pageMap) createSiteTaxonomies() error { } } - return nil + return walkErr } func (m *pageMap) createListAllPages() page.Pages { @@ -426,7 +431,6 @@ func (m *pageMap) assembleSections() error { m.sections.Walk(func(s string, v interface{}) bool { n := v.(*contentNode) - var shouldBuild bool defer func() { @@ -596,11 +600,12 @@ func (m *pageMap) attachPageToViews(s string, b *contentNode) { }, } - if s == "/" { - // To avoid getting an empty key. - s = page.KindHome + var key string + if strings.HasSuffix(s, "/") { + key = cleanSectionTreeKey(path.Join(viewName.plural, termKey, s)) + } else { + key = cleanTreeKey(path.Join(viewName.plural, termKey, s)) } - key := cleanTreeKey(path.Join(viewName.plural, termKey, s)) m.taxonomyEntries.Insert(key, bv) } } @@ -638,19 +643,10 @@ func (m *pageMap) collectPagesAndSections(query pageMapQuery, fn func(c *content } func (m *pageMap) collectSections(query pageMapQuery, fn func(c *contentNode)) error { - var level int - isHome := query.Prefix == "/" - - if !isHome { - level = strings.Count(query.Prefix, "/") - } + level := strings.Count(query.Prefix, "/") return m.collectSectionsFn(query, func(s string, c *contentNode) bool { - if s == query.Prefix { - return false - } - - if (strings.Count(s, "/") - level) != 1 { + if strings.Count(s, "/") != level+1 { return false } @@ -745,10 +741,11 @@ func (m *pageMaps) AssemblePages() error { return err } - a := (§ionWalker{m: pm.contentMap}).applyAggregates() + sw := §ionWalker{m: pm.contentMap} + a := sw.applyAggregates() _, mainSectionsSet := pm.s.s.Info.Params()["mainsections"] if !mainSectionsSet && a.mainSection != "" { - mainSections := []string{a.mainSection} + mainSections := []string{strings.TrimRight(a.mainSection, "/")} pm.s.s.Info.Params()["mainSections"] = mainSections pm.s.s.Info.Params()["mainsections"] = mainSections } @@ -847,7 +844,7 @@ func (b *pagesMapBucket) getTaxonomies() page.Pages { b.sectionsInit.Do(func() { var pas page.Pages ref := b.owner.treeRef - ref.m.collectTaxonomies(ref.key+"/", func(c *contentNode) { + ref.m.collectTaxonomies(ref.key, func(c *contentNode) { pas = append(pas, c.p) }) page.SortByDefault(pas) @@ -888,8 +885,12 @@ type sectionAggregateHandler struct { s string } +func (h *sectionAggregateHandler) String() string { + return fmt.Sprintf("%s/%s - %d - %s", h.sectionAggregate.datesAll, h.sectionAggregate.datesSection, h.sectionPageCount, h.s) +} + func (h *sectionAggregateHandler) isRootSection() bool { - return h.s != "/" && strings.Count(h.s, "/") == 1 + return h.s != "/" && strings.Count(h.s, "/") == 2 } func (h *sectionAggregateHandler) handleNested(v sectionWalkHandler) error { @@ -963,11 +964,13 @@ func (w *sectionWalker) applyAggregates() *sectionAggregateHandler { func (w *sectionWalker) walkLevel(prefix string, createVisitor func() sectionWalkHandler) sectionWalkHandler { level := strings.Count(prefix, "/") + visitor := createVisitor() - w.m.taxonomies.WalkPrefix(prefix, func(s string, v interface{}) bool { + w.m.taxonomies.WalkBelow(prefix, func(s string, v interface{}) bool { currentLevel := strings.Count(s, "/") - if currentLevel > level { + + if currentLevel > level+1 { return false } @@ -977,8 +980,8 @@ func (w *sectionWalker) walkLevel(prefix string, createVisitor func() sectionWal return true } - if currentLevel == 1 { - nested := w.walkLevel(s+"/", createVisitor) + if currentLevel == 2 { + nested := w.walkLevel(s, createVisitor) if w.err = visitor.handleNested(nested); w.err != nil { return true } @@ -995,9 +998,9 @@ func (w *sectionWalker) walkLevel(prefix string, createVisitor func() sectionWal return w.err != nil }) - w.m.sections.WalkPrefix(prefix, func(s string, v interface{}) bool { + w.m.sections.WalkBelow(prefix, func(s string, v interface{}) bool { currentLevel := strings.Count(s, "/") - if currentLevel > level { + if currentLevel > level+1 { return false } @@ -1016,11 +1019,9 @@ func (w *sectionWalker) walkLevel(prefix string, createVisitor func() sectionWal return true } - if s != "/" { - nested := w.walkLevel(s+"/", createVisitor) - if w.err = visitor.handleNested(nested); w.err != nil { - return true - } + nested := w.walkLevel(s, createVisitor) + if w.err = visitor.handleNested(nested); w.err != nil { + return true } w.err = visitor.handleSectionPost() diff --git a/hugolib/content_map_test.go b/hugolib/content_map_test.go index 4ddbf8c7f..9ec30201a 100644 --- a/hugolib/content_map_test.go +++ b/hugolib/content_map_test.go @@ -155,19 +155,19 @@ func TestContentMap(t *testing.T) { expect := ` Tree 0: - /blog__hb_/a__hl_ - /blog__hb_/b/c__hl_ + /blog/__hb_a__hl_ + /blog/__hb_b/c__hl_ Tree 1: - /blog + /blog/ Tree 2: - /blog__hb_/a__hl_b/data.json - /blog__hb_/a__hl_logo.png - /blog__hl_sectiondata.json - en/pages/blog__hb_/a__hl_|f:blog/a/index.md + /blog/__hb_a__hl_b/data.json + /blog/__hb_a__hl_logo.png + /blog/__hl_sectiondata.json + en/pages/blog/__hb_a__hl_|f:blog/a/index.md - R: blog/a/b/data.json - R: blog/a/logo.png - en/pages/blog__hb_/b/c__hl_|f:blog/b/c/index.md - en/sections/blog|f:blog/_index.md + en/pages/blog/__hb_b/c__hl_|f:blog/b/c/index.md + en/sections/blog/|f:blog/_index.md - P: blog/a/index.md - P: blog/b/c/index.md - R: blog/sectiondata.json @@ -194,24 +194,24 @@ func TestContentMap(t *testing.T) { expect = ` Tree 0: - /blog__hb_/a__hl_ - /blog__hb_/b/c__hl_ + /blog/__hb_a__hl_ + /blog/__hb_b/c__hl_ Tree 1: - /blog + /blog/ Tree 2: - /blog__hb_/a__hl_b/data.json - /blog__hb_/a__hl_b/data2.json - /blog__hb_/a__hl_logo.png - /blog__hb_/b/c__hl_d/data3.json - /blog__hl_sectiondata.json - /blog__hl_sectiondata2.json - en/pages/blog__hb_/a__hl_|f:blog/a/index.md + /blog/__hb_a__hl_b/data.json + /blog/__hb_a__hl_b/data2.json + /blog/__hb_a__hl_logo.png + /blog/__hb_b/c__hl_d/data3.json + /blog/__hl_sectiondata.json + /blog/__hl_sectiondata2.json + en/pages/blog/__hb_a__hl_|f:blog/a/index.md - R: blog/a/b/data.json - R: blog/a/b/data2.json - R: blog/a/logo.png - en/pages/blog__hb_/b/c__hl_|f:blog/b/c/index.md + en/pages/blog/__hb_b/c__hl_|f:blog/b/c/index.md - R: blog/b/c/d/data3.json - en/sections/blog|f:blog/_index.md + en/sections/blog/|f:blog/_index.md - P: blog/a/index.md - P: blog/b/c/index.md - R: blog/sectiondata.json @@ -226,26 +226,26 @@ func TestContentMap(t *testing.T) { c.Assert(m.testDump(), hqt.IsSameString, ` Tree 0: - /blog__hb_/a__hl_ - /blog__hb_/b/c__hl_ - /blog__hb_/b__hl_ + /blog/__hb_a__hl_ + /blog/__hb_b/c__hl_ + /blog/__hb_b__hl_ Tree 1: - /blog + /blog/ Tree 2: - /blog__hb_/a__hl_b/data.json - /blog__hb_/a__hl_b/data2.json - /blog__hb_/a__hl_logo.png - /blog__hb_/b/c__hl_d/data3.json - /blog__hl_sectiondata.json - /blog__hl_sectiondata2.json - en/pages/blog__hb_/a__hl_|f:blog/a/index.md + /blog/__hb_a__hl_b/data.json + /blog/__hb_a__hl_b/data2.json + /blog/__hb_a__hl_logo.png + /blog/__hb_b/c__hl_d/data3.json + /blog/__hl_sectiondata.json + /blog/__hl_sectiondata2.json + en/pages/blog/__hb_a__hl_|f:blog/a/index.md - R: blog/a/b/data.json - R: blog/a/b/data2.json - R: blog/a/logo.png - en/pages/blog__hb_/b/c__hl_|f:blog/b/c/index.md + en/pages/blog/__hb_b/c__hl_|f:blog/b/c/index.md - R: blog/b/c/d/data3.json - en/pages/blog__hb_/b__hl_|f:blog/b.md - en/sections/blog|f:blog/_index.md + en/pages/blog/__hb_b__hl_|f:blog/b.md + en/sections/blog/|f:blog/_index.md - P: blog/a/index.md - P: blog/b/c/index.md - P: blog/b.md @@ -280,19 +280,19 @@ func TestContentMap(t *testing.T) { c.Assert(got, hqt.IsSameString, ` Tree 0: - /__hb_/bundle__hl_ - /blog__hb_/a__hl_ - /blog__hb_/page__hl_ + /__hb_bundle__hl_ + /blog/__hb_a__hl_ + /blog/__hb_page__hl_ Tree 1: / - /blog + /blog/ Tree 2: - en/pages/__hb_/bundle__hl_|f:bundle/index.md - en/pages/blog__hb_/a__hl_|f:blog/a/index.md - en/pages/blog__hb_/page__hl_|f:blog/page.md + en/pages/__hb_bundle__hl_|f:bundle/index.md + en/pages/blog/__hb_a__hl_|f:blog/a/index.md + en/pages/blog/__hb_page__hl_|f:blog/page.md en/sections/ - P: bundle/index.md - en/sections/blog + en/sections/blog/ - P: blog/a/index.md - P: blog/page.md diff --git a/hugolib/page.go b/hugolib/page.go index bd518c1e1..dbcc31236 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -133,22 +133,21 @@ func (p *pageState) GitInfo() *gitmap.GitInfo { // GetTerms gets the terms defined on this page in the given taxonomy. func (p *pageState) GetTerms(taxonomy string) page.Pages { - taxonomy = strings.ToLower(taxonomy) + if p.treeRef == nil { + return nil + } + m := p.s.pageMap - prefix := cleanTreeKey(taxonomy) - var self string - if p.IsHome() { - // TODO(bep) make this less magical, see taxonomyEntries.Insert. - self = "/" + page.KindHome - } else if p.treeRef != nil { - self = p.treeRef.key - } + taxonomy = strings.ToLower(taxonomy) + prefix := cleanSectionTreeKey(taxonomy) + self := strings.TrimPrefix(p.treeRef.key, "/") var pas page.Pages m.taxonomies.WalkQuery(pageMapQuery{Prefix: prefix}, func(s string, n *contentNode) bool { - if _, found := m.taxonomyEntries.Get(s + self); found { + key := s + self + if _, found := m.taxonomyEntries.Get(key); found { pas = append(pas, n.p) } return false diff --git a/hugolib/page__tree.go b/hugolib/page__tree.go index a6f66ffbc..5b53dc4cd 100644 --- a/hugolib/page__tree.go +++ b/hugolib/page__tree.go @@ -58,7 +58,7 @@ func (pt pageTree) IsAncestor(other interface{}) (bool, error) { return true, nil } - if strings.HasPrefix(ref2.key, ref1.key+"/") { + if strings.HasPrefix(ref2.key, ref1.key) { return true, nil } @@ -109,7 +109,7 @@ func (pt pageTree) IsDescendant(other interface{}) (bool, error) { return true, nil } - if strings.HasPrefix(ref1.key, ref2.key+"/") { + if strings.HasPrefix(ref1.key, ref2.key) { return true, nil } @@ -123,9 +123,11 @@ func (pt pageTree) FirstSection() page.Page { return pt.p.s.home } key := ref.key + if !ref.isSection() { key = path.Dir(key) } + _, b := ref.m.getFirstSection(key) if b == nil { return nil diff --git a/hugolib/pagecollections.go b/hugolib/pagecollections.go index 7cdac7453..49378452f 100644 --- a/hugolib/pagecollections.go +++ b/hugolib/pagecollections.go @@ -169,18 +169,20 @@ func (c *PageCollections) getPageNew(context page.Page, ref string) (page.Page, func (c *PageCollections) getSectionOrPage(ref string) (*contentNode, string) { var n *contentNode - s, v, found := c.pageMap.sections.LongestPrefix(ref) + pref := helpers.AddTrailingSlash(ref) + s, v, found := c.pageMap.sections.LongestPrefix(pref) if found { n = v.(*contentNode) } - if found && s == ref { + if found && s == pref { // A section return n, "" } m := c.pageMap + filename := strings.TrimPrefix(strings.TrimPrefix(ref, s), "/") langSuffix := "." + m.s.Lang() @@ -224,9 +226,11 @@ func shouldDoSimpleLookup(ref string) bool { func (c *PageCollections) getContentNode(context page.Page, isReflink bool, ref string) (*contentNode, error) { ref = filepath.ToSlash(strings.ToLower(strings.TrimSpace(ref))) + if ref == "" { ref = "/" } + inRef := ref navUp := strings.HasPrefix(ref, "..") var doSimpleLookup bool @@ -275,9 +279,11 @@ func (c *PageCollections) getContentNode(context page.Page, isReflink bool, ref } // Check if it's a taxonomy node - s, v, found := m.taxonomies.LongestPrefix(ref) + pref := helpers.AddTrailingSlash(ref) + s, v, found := m.taxonomies.LongestPrefix(pref) + if found { - if !m.onSameLevel(ref, s) { + if !m.onSameLevel(pref, s) { return nil, nil } return v.(*contentNode), nil diff --git a/hugolib/pagecollections_test.go b/hugolib/pagecollections_test.go index bf3832c96..bb846da85 100644 --- a/hugolib/pagecollections_test.go +++ b/hugolib/pagecollections_test.go @@ -211,6 +211,9 @@ func TestGetPage(t *testing.T) { writeSource(t, fs, filepath.Join("content", "sect3", "b1", "index.md"), pc("b1 bundle")) writeSource(t, fs, filepath.Join("content", "sect3", "index", "index.md"), pc("index bundle")) + writeSource(t, fs, filepath.Join("content", "section_bundle_overlap", "_index.md"), pc("index overlap section")) + writeSource(t, fs, filepath.Join("content", "section_bundle_overlap_bundle", "index.md"), pc("index overlap bundle")) + s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{SkipRender: true}) sec3, err := s.getPageNew(nil, "/sect3") @@ -282,6 +285,9 @@ func TestGetPage(t *testing.T) { // Bundle variants {"Bundle regular", page.KindPage, nil, []string{"sect3/b1", "sect3/b1/index.md", "sect3/b1/index.en.md"}, "b1 bundle"}, {"Bundle index name", page.KindPage, nil, []string{"sect3/index/index.md", "sect3/index"}, "index bundle"}, + + // https://github.com/gohugoio/hugo/issues/7301 + {"Section and bundle overlap", page.KindPage, nil, []string{"section_bundle_overlap_bundle"}, "index overlap bundle"}, } for _, test := range tests { diff --git a/hugolib/taxonomy_test.go b/hugolib/taxonomy_test.go index f37e37b89..1f43318fa 100644 --- a/hugolib/taxonomy_test.go +++ b/hugolib/taxonomy_test.go @@ -637,6 +637,7 @@ Cats Paginator {{ range $cats.Paginator.Pages }}{{ .RelPermalink }}|{{ end }}:EN b.Assert(funny, qt.Not(qt.IsNil)) b.Assert(cat.Parent().IsHome(), qt.Equals, true) + b.Assert(funny.Kind(), qt.Equals, "taxonomy") b.Assert(funny.Parent(), qt.Equals, cat) b.AssertFileContent("public/index.html", ` |