Allow headless bundles to list pages via $page.Pages and $page.RegularPages
Fixes #7075
This commit is contained in:
parent
1d91d8e14b
commit
99958f90fe
10 changed files with 288 additions and 72 deletions
|
@ -21,7 +21,7 @@ They are stored in a reserved Front Matter object named `_build` with the follow
|
||||||
```yaml
|
```yaml
|
||||||
_build:
|
_build:
|
||||||
render: true
|
render: true
|
||||||
list: true
|
list: always
|
||||||
publishResources: true
|
publishResources: true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -29,6 +29,20 @@ _build:
|
||||||
If true, the page will be treated as a published page, holding its dedicated output files (`index.html`, etc...) and permalink.
|
If true, the page will be treated as a published page, holding its dedicated output files (`index.html`, etc...) and permalink.
|
||||||
|
|
||||||
#### list
|
#### list
|
||||||
|
|
||||||
|
Note that we extended this property from a boolean to an enum in Hugo 0.58.0.
|
||||||
|
|
||||||
|
Valid values are:
|
||||||
|
|
||||||
|
never
|
||||||
|
: The page will not be incldued in any page collection.
|
||||||
|
|
||||||
|
always (default)
|
||||||
|
: The page will be included in all page collections, e.g. `site.RegularPages`, `$page.Pages`.
|
||||||
|
|
||||||
|
local
|
||||||
|
: The page will be included in any _local_ page collection, e.g. `$page.RegularPages`, `$page.Pages`. One use case for this would be to create fully navigable, but headless content sections. {{< new-in "0.58.0" >}}
|
||||||
|
|
||||||
If true, the page will be treated as part of the project's collections and, when appropriate, returned by Hugo's listing methods (`.Pages`, `.RegularPages` etc...).
|
If true, the page will be treated as part of the project's collections and, when appropriate, returned by Hugo's listing methods (`.Pages`, `.RegularPages` etc...).
|
||||||
|
|
||||||
#### publishResources
|
#### publishResources
|
||||||
|
|
|
@ -789,6 +789,12 @@ func (t contentTrees) DeletePrefix(prefix string) int {
|
||||||
|
|
||||||
type contentTreeNodeCallback func(s string, n *contentNode) bool
|
type contentTreeNodeCallback func(s string, n *contentNode) bool
|
||||||
|
|
||||||
|
func newContentTreeFilter(fn func(n *contentNode) bool) contentTreeNodeCallback {
|
||||||
|
return func(s string, n *contentNode) bool {
|
||||||
|
return fn(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
contentTreeNoListFilter = func(s string, n *contentNode) bool {
|
contentTreeNoListFilter = func(s string, n *contentNode) bool {
|
||||||
if n.p == nil {
|
if n.p == nil {
|
||||||
|
@ -805,43 +811,36 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *contentTree) WalkPrefixListable(prefix string, fn contentTreeNodeCallback) {
|
func (c *contentTree) WalkQuery(query pageMapQuery, walkFn contentTreeNodeCallback) {
|
||||||
c.WalkPrefixFilter(prefix, contentTreeNoListFilter, fn)
|
filter := query.Filter
|
||||||
}
|
if filter == nil {
|
||||||
|
filter = contentTreeNoListFilter
|
||||||
|
}
|
||||||
|
if query.Prefix != "" {
|
||||||
|
c.WalkPrefix(query.Prefix, func(s string, v interface{}) bool {
|
||||||
|
n := v.(*contentNode)
|
||||||
|
if filter != nil && filter(s, n) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return walkFn(s, n)
|
||||||
|
})
|
||||||
|
|
||||||
func (c *contentTree) WalkPrefixFilter(prefix string, filter, walkFn contentTreeNodeCallback) {
|
return
|
||||||
c.WalkPrefix(prefix, func(s string, v interface{}) bool {
|
}
|
||||||
n := v.(*contentNode)
|
|
||||||
if filter(s, n) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return walkFn(s, n)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *contentTree) WalkListable(fn contentTreeNodeCallback) {
|
|
||||||
c.WalkFilter(contentTreeNoListFilter, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *contentTree) WalkFilter(filter, walkFn contentTreeNodeCallback) {
|
|
||||||
c.Walk(func(s string, v interface{}) bool {
|
c.Walk(func(s string, v interface{}) bool {
|
||||||
n := v.(*contentNode)
|
n := v.(*contentNode)
|
||||||
if filter(s, n) {
|
if filter != nil && filter(s, n) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return walkFn(s, n)
|
return walkFn(s, n)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c contentTrees) WalkListable(fn contentTreeNodeCallback) {
|
|
||||||
for _, tree := range c {
|
|
||||||
tree.WalkListable(fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c contentTrees) WalkRenderable(fn contentTreeNodeCallback) {
|
func (c contentTrees) WalkRenderable(fn contentTreeNodeCallback) {
|
||||||
|
query := pageMapQuery{Filter: contentTreeNoRenderFilter}
|
||||||
for _, tree := range c {
|
for _, tree := range c {
|
||||||
tree.WalkFilter(contentTreeNoRenderFilter, fn)
|
tree.WalkQuery(query, fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -931,44 +930,73 @@ func (c *contentTreeRef) getSection() (string, *contentNode) {
|
||||||
return c.m.getSection(c.key)
|
return c.m.getSection(c.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentTreeRef) collectPages() page.Pages {
|
func (c *contentTreeRef) getPages() page.Pages {
|
||||||
var pas page.Pages
|
var pas page.Pages
|
||||||
c.m.collectPages(c.key+cmBranchSeparator, func(c *contentNode) {
|
c.m.collectPages(
|
||||||
pas = append(pas, c.p)
|
pageMapQuery{
|
||||||
})
|
Prefix: c.key + cmBranchSeparator,
|
||||||
|
Filter: c.n.p.m.getListFilter(true),
|
||||||
|
},
|
||||||
|
func(c *contentNode) {
|
||||||
|
pas = append(pas, c.p)
|
||||||
|
},
|
||||||
|
)
|
||||||
page.SortByDefault(pas)
|
page.SortByDefault(pas)
|
||||||
|
|
||||||
return pas
|
return pas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentTreeRef) collectPagesRecursive() page.Pages {
|
func (c *contentTreeRef) getPagesRecursive() page.Pages {
|
||||||
var pas page.Pages
|
var pas page.Pages
|
||||||
c.m.collectPages(c.key+cmBranchSeparator, func(c *contentNode) {
|
|
||||||
|
query := pageMapQuery{
|
||||||
|
Filter: c.n.p.m.getListFilter(true),
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Prefix = c.key + cmBranchSeparator
|
||||||
|
c.m.collectPages(query, func(c *contentNode) {
|
||||||
pas = append(pas, c.p)
|
pas = append(pas, c.p)
|
||||||
})
|
})
|
||||||
c.m.collectPages(c.key+"/", func(c *contentNode) {
|
|
||||||
|
query.Prefix = c.key + "/"
|
||||||
|
c.m.collectPages(query, func(c *contentNode) {
|
||||||
pas = append(pas, c.p)
|
pas = append(pas, c.p)
|
||||||
})
|
})
|
||||||
|
|
||||||
page.SortByDefault(pas)
|
page.SortByDefault(pas)
|
||||||
|
|
||||||
return pas
|
return pas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentTreeRef) collectPagesAndSections() page.Pages {
|
func (c *contentTreeRef) getPagesAndSections() page.Pages {
|
||||||
var pas page.Pages
|
var pas page.Pages
|
||||||
c.m.collectPagesAndSections(c.key, func(c *contentNode) {
|
|
||||||
|
query := pageMapQuery{
|
||||||
|
Filter: c.n.p.m.getListFilter(true),
|
||||||
|
Prefix: c.key,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.m.collectPagesAndSections(query, func(c *contentNode) {
|
||||||
pas = append(pas, c.p)
|
pas = append(pas, c.p)
|
||||||
})
|
})
|
||||||
|
|
||||||
page.SortByDefault(pas)
|
page.SortByDefault(pas)
|
||||||
|
|
||||||
return pas
|
return pas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentTreeRef) collectSections() page.Pages {
|
func (c *contentTreeRef) getSections() page.Pages {
|
||||||
var pas page.Pages
|
var pas page.Pages
|
||||||
c.m.collectSections(c.key, func(c *contentNode) {
|
|
||||||
|
query := pageMapQuery{
|
||||||
|
Filter: c.n.p.m.getListFilter(true),
|
||||||
|
Prefix: c.key,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.m.collectSections(query, func(c *contentNode) {
|
||||||
pas = append(pas, c.p)
|
pas = append(pas, c.p)
|
||||||
})
|
})
|
||||||
|
|
||||||
page.SortByDefault(pas)
|
page.SortByDefault(pas)
|
||||||
|
|
||||||
return pas
|
return pas
|
||||||
|
|
|
@ -606,36 +606,47 @@ func (m *pageMap) attachPageToViews(s string, b *contentNode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *pageMap) collectPages(prefix string, fn func(c *contentNode)) error {
|
type pageMapQuery struct {
|
||||||
m.pages.WalkPrefixListable(prefix, func(s string, n *contentNode) bool {
|
Prefix string
|
||||||
|
Filter contentTreeNodeCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *pageMap) collectPages(query pageMapQuery, fn func(c *contentNode)) error {
|
||||||
|
if query.Filter == nil {
|
||||||
|
query.Filter = contentTreeNoListFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
m.pages.WalkQuery(query, func(s string, n *contentNode) bool {
|
||||||
fn(n)
|
fn(n)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *pageMap) collectPagesAndSections(prefix string, fn func(c *contentNode)) error {
|
func (m *pageMap) collectPagesAndSections(query pageMapQuery, fn func(c *contentNode)) error {
|
||||||
if err := m.collectSections(prefix, fn); err != nil {
|
if err := m.collectSections(query, fn); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := m.collectPages(prefix+cmBranchSeparator, fn); err != nil {
|
query.Prefix = query.Prefix + cmBranchSeparator
|
||||||
|
if err := m.collectPages(query, fn); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *pageMap) collectSections(prefix string, fn func(c *contentNode)) error {
|
func (m *pageMap) collectSections(query pageMapQuery, fn func(c *contentNode)) error {
|
||||||
var level int
|
var level int
|
||||||
isHome := prefix == "/"
|
isHome := query.Prefix == "/"
|
||||||
|
|
||||||
if !isHome {
|
if !isHome {
|
||||||
level = strings.Count(prefix, "/")
|
level = strings.Count(query.Prefix, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.collectSectionsFn(prefix, func(s string, c *contentNode) bool {
|
return m.collectSectionsFn(query, func(s string, c *contentNode) bool {
|
||||||
if s == prefix {
|
if s == query.Prefix {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,27 +660,28 @@ func (m *pageMap) collectSections(prefix string, fn func(c *contentNode)) error
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *pageMap) collectSectionsFn(prefix string, fn func(s string, c *contentNode) bool) error {
|
func (m *pageMap) collectSectionsFn(query pageMapQuery, fn func(s string, c *contentNode) bool) error {
|
||||||
if !strings.HasSuffix(prefix, "/") {
|
|
||||||
prefix += "/"
|
if !strings.HasSuffix(query.Prefix, "/") {
|
||||||
|
query.Prefix += "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
m.sections.WalkPrefixListable(prefix, func(s string, n *contentNode) bool {
|
m.sections.WalkQuery(query, func(s string, n *contentNode) bool {
|
||||||
return fn(s, n)
|
return fn(s, n)
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *pageMap) collectSectionsRecursiveIncludingSelf(prefix string, fn func(c *contentNode)) error {
|
func (m *pageMap) collectSectionsRecursiveIncludingSelf(query pageMapQuery, fn func(c *contentNode)) error {
|
||||||
return m.collectSectionsFn(prefix, func(s string, c *contentNode) bool {
|
return m.collectSectionsFn(query, func(s string, c *contentNode) bool {
|
||||||
fn(c)
|
fn(c)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *pageMap) collectTaxonomies(prefix string, fn func(c *contentNode)) error {
|
func (m *pageMap) collectTaxonomies(prefix string, fn func(c *contentNode)) error {
|
||||||
m.taxonomies.WalkPrefixListable(prefix, func(s string, n *contentNode) bool {
|
m.taxonomies.WalkQuery(pageMapQuery{Prefix: prefix}, func(s string, n *contentNode) bool {
|
||||||
fn(n)
|
fn(n)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
@ -797,21 +809,21 @@ type pagesMapBucket struct {
|
||||||
|
|
||||||
func (b *pagesMapBucket) getPages() page.Pages {
|
func (b *pagesMapBucket) getPages() page.Pages {
|
||||||
b.pagesInit.Do(func() {
|
b.pagesInit.Do(func() {
|
||||||
b.pages = b.owner.treeRef.collectPages()
|
b.pages = b.owner.treeRef.getPages()
|
||||||
page.SortByDefault(b.pages)
|
page.SortByDefault(b.pages)
|
||||||
})
|
})
|
||||||
return b.pages
|
return b.pages
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *pagesMapBucket) getPagesRecursive() page.Pages {
|
func (b *pagesMapBucket) getPagesRecursive() page.Pages {
|
||||||
pages := b.owner.treeRef.collectPagesRecursive()
|
pages := b.owner.treeRef.getPagesRecursive()
|
||||||
page.SortByDefault(pages)
|
page.SortByDefault(pages)
|
||||||
return pages
|
return pages
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *pagesMapBucket) getPagesAndSections() page.Pages {
|
func (b *pagesMapBucket) getPagesAndSections() page.Pages {
|
||||||
b.pagesAndSectionsInit.Do(func() {
|
b.pagesAndSectionsInit.Do(func() {
|
||||||
b.pagesAndSections = b.owner.treeRef.collectPagesAndSections()
|
b.pagesAndSections = b.owner.treeRef.getPagesAndSections()
|
||||||
})
|
})
|
||||||
return b.pagesAndSections
|
return b.pagesAndSections
|
||||||
}
|
}
|
||||||
|
@ -821,7 +833,7 @@ func (b *pagesMapBucket) getSections() page.Pages {
|
||||||
if b.owner.treeRef == nil {
|
if b.owner.treeRef == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b.sections = b.owner.treeRef.collectSections()
|
b.sections = b.owner.treeRef.getSections()
|
||||||
})
|
})
|
||||||
|
|
||||||
return b.sections
|
return b.sections
|
||||||
|
|
|
@ -66,7 +66,26 @@ title: Headless
|
||||||
headless: true
|
headless: true
|
||||||
---
|
---
|
||||||
|
|
||||||
`)
|
|
||||||
|
`, "headless-local/_index.md", `
|
||||||
|
---
|
||||||
|
title: Headless Local Lists
|
||||||
|
cascade:
|
||||||
|
_build:
|
||||||
|
render: false
|
||||||
|
list: local
|
||||||
|
publishResources: false
|
||||||
|
---
|
||||||
|
|
||||||
|
`, "headless-local/headless-local-page.md", "---\ntitle: Headless Local Page\n---",
|
||||||
|
"headless-local/sub/_index.md", `
|
||||||
|
---
|
||||||
|
title: Headless Local Lists Sub
|
||||||
|
---
|
||||||
|
|
||||||
|
`, "headless-local/sub/headless-local-sub-page.md", "---\ntitle: Headless Local Sub Page\n---",
|
||||||
|
)
|
||||||
|
|
||||||
b.WithSourceFile("content/sect/headlessbundle/data.json", "DATA")
|
b.WithSourceFile("content/sect/headlessbundle/data.json", "DATA")
|
||||||
b.WithSourceFile("content/sect/no-publishresources/data.json", "DATA")
|
b.WithSourceFile("content/sect/no-publishresources/data.json", "DATA")
|
||||||
|
|
||||||
|
@ -93,8 +112,11 @@ headless: true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
getPageInPagePages := func(p page.Page, ref string) page.Page {
|
getPageInPagePages := func(p page.Page, ref string, pageCollections ...page.Pages) page.Page {
|
||||||
for _, pages := range []page.Pages{p.Pages(), p.RegularPages(), p.Sections()} {
|
if len(pageCollections) == 0 {
|
||||||
|
pageCollections = []page.Pages{p.Pages(), p.RegularPages(), p.RegularPagesRecursive(), p.Sections()}
|
||||||
|
}
|
||||||
|
for _, pages := range pageCollections {
|
||||||
for _, p := range pages {
|
for _, p := range pages {
|
||||||
if ref == p.(*pageState).sourceRef() {
|
if ref == p.(*pageState).sourceRef() {
|
||||||
return p
|
return p
|
||||||
|
@ -240,6 +262,33 @@ headless: true
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
c.Run("Build config, local list", func(c *qt.C) {
|
||||||
|
b := newSitesBuilder(c, disableKind)
|
||||||
|
b.Build(BuildCfg{})
|
||||||
|
ref := "/headless-local"
|
||||||
|
sect := getPage(b, ref)
|
||||||
|
b.Assert(sect, qt.Not(qt.IsNil))
|
||||||
|
b.Assert(getPageInSitePages(b, ref), qt.IsNil)
|
||||||
|
b.Assert(getPageInSitePages(b, ref+"/headless-local-page"), qt.IsNil)
|
||||||
|
for i, p := range sect.RegularPages() {
|
||||||
|
fmt.Println("REG", i, p.(*pageState).sourceRef())
|
||||||
|
}
|
||||||
|
|
||||||
|
localPageRef := ref + "/headless-local-page.md"
|
||||||
|
|
||||||
|
b.Assert(getPageInPagePages(sect, localPageRef, sect.RegularPages()), qt.Not(qt.IsNil))
|
||||||
|
b.Assert(getPageInPagePages(sect, localPageRef, sect.RegularPagesRecursive()), qt.Not(qt.IsNil))
|
||||||
|
b.Assert(getPageInPagePages(sect, localPageRef, sect.Pages()), qt.Not(qt.IsNil))
|
||||||
|
|
||||||
|
ref = "/headless-local/sub"
|
||||||
|
|
||||||
|
sect = getPage(b, ref)
|
||||||
|
b.Assert(sect, qt.Not(qt.IsNil))
|
||||||
|
|
||||||
|
localPageRef = ref + "/headless-local-sub-page.md"
|
||||||
|
b.Assert(getPageInPagePages(sect, localPageRef), qt.Not(qt.IsNil))
|
||||||
|
})
|
||||||
|
|
||||||
c.Run("Build config, no render", func(c *qt.C) {
|
c.Run("Build config, no render", func(c *qt.C) {
|
||||||
b := newSitesBuilder(c, disableKind)
|
b := newSitesBuilder(c, disableKind)
|
||||||
b.Build(BuildCfg{})
|
b.Build(BuildCfg{})
|
||||||
|
|
|
@ -147,7 +147,7 @@ func (p *pageState) GetTerms(taxonomy string) page.Pages {
|
||||||
|
|
||||||
var pas page.Pages
|
var pas page.Pages
|
||||||
|
|
||||||
m.taxonomies.WalkPrefixListable(prefix, func(s string, n *contentNode) bool {
|
m.taxonomies.WalkQuery(pageMapQuery{Prefix: prefix}, func(s string, n *contentNode) bool {
|
||||||
if _, found := m.taxonomyEntries.Get(s + self); found {
|
if _, found := m.taxonomyEntries.Get(s + self); found {
|
||||||
pas = append(pas, n.p)
|
pas = append(pas, n.p)
|
||||||
}
|
}
|
||||||
|
|
|
@ -460,7 +460,7 @@ func (pm *pageMeta) setMetadata(parentBucket *pagesMapBucket, p *pageState, fron
|
||||||
isHeadless := cast.ToBool(v)
|
isHeadless := cast.ToBool(v)
|
||||||
pm.params[loki] = isHeadless
|
pm.params[loki] = isHeadless
|
||||||
if p.File().TranslationBaseName() == "index" && isHeadless {
|
if p.File().TranslationBaseName() == "index" && isHeadless {
|
||||||
pm.buildConfig.List = false
|
pm.buildConfig.List = pagemeta.Never
|
||||||
pm.buildConfig.Render = false
|
pm.buildConfig.Render = false
|
||||||
}
|
}
|
||||||
case "outputs":
|
case "outputs":
|
||||||
|
@ -613,7 +613,28 @@ func (pm *pageMeta) setMetadata(parentBucket *pagesMapBucket, p *pageState, fron
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pageMeta) noList() bool {
|
func (p *pageMeta) noList() bool {
|
||||||
return !p.buildConfig.List
|
return !p.buildConfig.ShouldList()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pageMeta) getListFilter(local bool) contentTreeNodeCallback {
|
||||||
|
|
||||||
|
return newContentTreeFilter(func(n *contentNode) bool {
|
||||||
|
if n == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var shouldList bool
|
||||||
|
switch n.p.m.buildConfig.List {
|
||||||
|
case pagemeta.Always:
|
||||||
|
shouldList = true
|
||||||
|
case pagemeta.Never:
|
||||||
|
shouldList = false
|
||||||
|
case pagemeta.ListLocally:
|
||||||
|
shouldList = local
|
||||||
|
}
|
||||||
|
|
||||||
|
return !shouldList
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pageMeta) noRender() bool {
|
func (p *pageMeta) noRender() bool {
|
||||||
|
|
|
@ -248,7 +248,7 @@ func (s *Site) prepareInits() {
|
||||||
s.init.prevNextInSection = init.Branch(func() (interface{}, error) {
|
s.init.prevNextInSection = init.Branch(func() (interface{}, error) {
|
||||||
|
|
||||||
var sections page.Pages
|
var sections page.Pages
|
||||||
s.home.treeRef.m.collectSectionsRecursiveIncludingSelf(s.home.treeRef.key, func(n *contentNode) {
|
s.home.treeRef.m.collectSectionsRecursiveIncludingSelf(pageMapQuery{Prefix: s.home.treeRef.key}, func(n *contentNode) {
|
||||||
sections = append(sections, n.p)
|
sections = append(sections, n.p)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ func (s *Site) prepareInits() {
|
||||||
treeRef := sect.(treeRefProvider).getTreeRef()
|
treeRef := sect.(treeRefProvider).getTreeRef()
|
||||||
|
|
||||||
var pas page.Pages
|
var pas page.Pages
|
||||||
treeRef.m.collectPages(treeRef.key+cmBranchSeparator, func(c *contentNode) {
|
treeRef.m.collectPages(pageMapQuery{Prefix: treeRef.key + cmBranchSeparator}, func(c *contentNode) {
|
||||||
pas = append(pas, c.p)
|
pas = append(pas, c.p)
|
||||||
})
|
})
|
||||||
page.SortByDefault(pas)
|
page.SortByDefault(pas)
|
||||||
|
@ -293,7 +293,7 @@ func (s *Site) prepareInits() {
|
||||||
treeRef := s.home.getTreeRef()
|
treeRef := s.home.getTreeRef()
|
||||||
|
|
||||||
var pas page.Pages
|
var pas page.Pages
|
||||||
treeRef.m.collectPages(treeRef.key+cmBranchSeparator, func(c *contentNode) {
|
treeRef.m.collectPages(pageMapQuery{Prefix: treeRef.key + cmBranchSeparator}, func(c *contentNode) {
|
||||||
pas = append(pas, c.p)
|
pas = append(pas, c.p)
|
||||||
})
|
})
|
||||||
page.SortByDefault(pas)
|
page.SortByDefault(pas)
|
||||||
|
|
|
@ -1021,7 +1021,7 @@ func printStringIndexes(s string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func isCI() bool {
|
func isCI() bool {
|
||||||
return os.Getenv("CI") != "" && os.Getenv("CIRCLE_BRANCH") == ""
|
return (os.Getenv("CI") != "" || os.Getenv("CI_LOCAL") != "") && os.Getenv("CIRCLE_BRANCH") == ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://github.com/golang/go/issues/19280
|
// See https://github.com/golang/go/issues/19280
|
||||||
|
|
|
@ -24,8 +24,14 @@ type URLPath struct {
|
||||||
Section string
|
Section string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Never = "never"
|
||||||
|
Always = "always"
|
||||||
|
ListLocally = "local"
|
||||||
|
)
|
||||||
|
|
||||||
var defaultBuildConfig = BuildConfig{
|
var defaultBuildConfig = BuildConfig{
|
||||||
List: true,
|
List: Always,
|
||||||
Render: true,
|
Render: true,
|
||||||
PublishResources: true,
|
PublishResources: true,
|
||||||
set: true,
|
set: true,
|
||||||
|
@ -35,8 +41,12 @@ var defaultBuildConfig = BuildConfig{
|
||||||
// build process.
|
// build process.
|
||||||
type BuildConfig struct {
|
type BuildConfig struct {
|
||||||
// Whether to add it to any of the page collections.
|
// Whether to add it to any of the page collections.
|
||||||
// Note that the page can still be found with .Site.GetPage.
|
// Note that the page can always be found with .Site.GetPage.
|
||||||
List bool
|
// Valid values: never, always, local.
|
||||||
|
// Setting it to 'local' means they will be available via the local
|
||||||
|
// page collections, e.g. $section.Pages.
|
||||||
|
// Note: before 0.57.2 this was a bool, so we accept those too.
|
||||||
|
List string
|
||||||
|
|
||||||
// Whether to render it.
|
// Whether to render it.
|
||||||
Render bool
|
Render bool
|
||||||
|
@ -51,7 +61,7 @@ type BuildConfig struct {
|
||||||
|
|
||||||
// Disable sets all options to their off value.
|
// Disable sets all options to their off value.
|
||||||
func (b *BuildConfig) Disable() {
|
func (b *BuildConfig) Disable() {
|
||||||
b.List = false
|
b.List = Never
|
||||||
b.Render = false
|
b.Render = false
|
||||||
b.PublishResources = false
|
b.PublishResources = false
|
||||||
b.set = true
|
b.set = true
|
||||||
|
@ -61,11 +71,29 @@ func (b BuildConfig) IsZero() bool {
|
||||||
return !b.set
|
return !b.set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BuildConfig) ShouldList() bool {
|
||||||
|
return b.List == Always || b.List == ListLocally
|
||||||
|
}
|
||||||
|
|
||||||
func DecodeBuildConfig(m interface{}) (BuildConfig, error) {
|
func DecodeBuildConfig(m interface{}) (BuildConfig, error) {
|
||||||
b := defaultBuildConfig
|
b := defaultBuildConfig
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := mapstructure.WeakDecode(m, &b)
|
err := mapstructure.WeakDecode(m, &b)
|
||||||
|
|
||||||
|
// In 0.67.1 we changed the list attribute from a bool to a string (enum).
|
||||||
|
// Bool values will become 0 or 1.
|
||||||
|
switch b.List {
|
||||||
|
case "0":
|
||||||
|
b.List = Never
|
||||||
|
case "1":
|
||||||
|
b.List = Always
|
||||||
|
case Always, Never, ListLocally:
|
||||||
|
default:
|
||||||
|
b.List = Always
|
||||||
|
}
|
||||||
|
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
64
resources/page/pagemeta/pagemeta_test.go
Normal file
64
resources/page/pagemeta/pagemeta_test.go
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright 2020 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 pagemeta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/htesting/hqt"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
|
qt "github.com/frankban/quicktest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDecodeBuildConfig(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
c := qt.New(t)
|
||||||
|
|
||||||
|
configTempl := `
|
||||||
|
[_build]
|
||||||
|
render = true
|
||||||
|
list = %s
|
||||||
|
publishResources = true`
|
||||||
|
|
||||||
|
for _, test := range []struct {
|
||||||
|
list interface{}
|
||||||
|
expect string
|
||||||
|
}{
|
||||||
|
{"true", Always},
|
||||||
|
{"false", Never},
|
||||||
|
{`"always"`, Always},
|
||||||
|
{`"local"`, ListLocally},
|
||||||
|
{`"asdfadf"`, Always},
|
||||||
|
} {
|
||||||
|
cfg, err := config.FromConfigString(fmt.Sprintf(configTempl, test.list), "toml")
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
bcfg, err := DecodeBuildConfig(cfg.Get("_build"))
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
eq := qt.CmpEquals(hqt.DeepAllowUnexported(BuildConfig{}))
|
||||||
|
|
||||||
|
c.Assert(bcfg, eq, BuildConfig{
|
||||||
|
Render: true,
|
||||||
|
List: test.expect,
|
||||||
|
PublishResources: true,
|
||||||
|
set: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue