pagemeta: Make BuildConfig.Render an enum

Allowing links on pages without rendering them.

Fixes #7783
This commit is contained in:
Bjørn Erik Pedersen 2020-10-06 11:19:31 +02:00
parent c63db7f1f6
commit 634938908e
6 changed files with 107 additions and 25 deletions

View file

@ -20,13 +20,24 @@ They are stored in a reserved Front Matter object named `_build` with the follow
```yaml ```yaml
_build: _build:
render: true render: always
list: always list: always
publishResources: true publishResources: true
``` ```
#### render #### render
If true, the page will be treated as a published page, holding its dedicated output files (`index.html`, etc...) and permalink. If `always`, the page will be treated as a published page, holding its dedicated output files (`index.html`, etc...) and permalink.
{{< new-in "0.76.0" >}} We extended this property from a boolean to an enum in Hugo 0.76.0. Valid values are:
never
: The page will not be included in any page collection.
always (default)
: The page will be rendered to disk and get a `RelPermalink` etc.
link
: The page will be not be rendered to disk, but will get a `RelPermalink`.
#### list #### list

View file

@ -54,7 +54,15 @@ title: No List
_build: _build:
render: false render: false
--- ---
`, "sect/no-publishresources/index.md", ` `,
"sect/no-render-link.md", `
---
title: No Render Link
_build:
render: link
---
`,
"sect/no-publishresources/index.md", `
--- ---
title: No Publish Resources title: No Publish Resources
_build: _build:
@ -303,6 +311,20 @@ title: Headless Local Lists Sub
b.Assert(getPageInPagePages(sect, ref), qt.Not(qt.IsNil)) b.Assert(getPageInPagePages(sect, ref), qt.Not(qt.IsNil))
}) })
c.Run("Build config, no render link", func(c *qt.C) {
b := newSitesBuilder(c, disableKind)
b.Build(BuildCfg{})
ref := "/sect/no-render-link.md"
b.Assert(b.CheckExists("public/sect/no-render/index.html"), qt.Equals, false)
p := getPage(b, ref)
b.Assert(p, qt.Not(qt.IsNil))
b.Assert(p.RelPermalink(), qt.Equals, "/blog/sect/no-render-link/")
b.Assert(p.OutputFormats(), qt.HasLen, 0)
b.Assert(getPageInSitePages(b, ref), qt.Not(qt.IsNil))
sect := getPage(b, "/sect")
b.Assert(getPageInPagePages(sect, ref), qt.Not(qt.IsNil))
})
c.Run("Build config, no publish resources", func(c *qt.C) { c.Run("Build config, no publish resources", func(c *qt.C) {
b := newSitesBuilder(c, disableKind) b := newSitesBuilder(c, disableKind)
b.Build(BuildCfg{}) b.Build(BuildCfg{})

View file

@ -506,7 +506,7 @@ func (pm *pageMeta) setMetadata(parentBucket *pagesMapBucket, p *pageState, fron
pm.params[loki] = isHeadless pm.params[loki] = isHeadless
if p.File().TranslationBaseName() == "index" && isHeadless { if p.File().TranslationBaseName() == "index" && isHeadless {
pm.buildConfig.List = pagemeta.Never pm.buildConfig.List = pagemeta.Never
pm.buildConfig.Render = false pm.buildConfig.Render = pagemeta.Never
} }
case "outputs": case "outputs":
o := cast.ToStringSlice(v) o := cast.ToStringSlice(v)
@ -683,7 +683,11 @@ func (p *pageMeta) getListFilter(local bool) contentTreeNodeCallback {
} }
func (p *pageMeta) noRender() bool { func (p *pageMeta) noRender() bool {
return !p.buildConfig.Render return p.buildConfig.Render != pagemeta.Always
}
func (p *pageMeta) noLink() bool {
return p.buildConfig.Render == pagemeta.Never
} }
func (p *pageMeta) applyDefaultValues(n *contentNode) error { func (p *pageMeta) applyDefaultValues(n *contentNode) error {

View file

@ -51,9 +51,11 @@ func newPagePaths(
var relPermalink, permalink string var relPermalink, permalink string
// If a page is headless or marked as "no render", or bundled in another, // If a page is headless or bundled in another,
// it will not get published on its own and it will have no links. // it will not get published on its own and it will have no links.
if !pm.noRender() && !pm.bundled { // We also check the build options if it's set to not render or have
// a link.
if !pm.noLink() && !pm.bundled {
relPermalink = paths.RelPermalink(s.PathSpec) relPermalink = paths.RelPermalink(s.PathSpec)
permalink = paths.PermalinkForOutputFormat(s.PathSpec, f) permalink = paths.PermalinkForOutputFormat(s.PathSpec, f)
} }

View file

@ -28,11 +28,12 @@ const (
Never = "never" Never = "never"
Always = "always" Always = "always"
ListLocally = "local" ListLocally = "local"
Link = "link"
) )
var defaultBuildConfig = BuildConfig{ var defaultBuildConfig = BuildConfig{
List: Always, List: Always,
Render: true, Render: Always,
PublishResources: true, PublishResources: true,
set: true, set: true,
} }
@ -49,7 +50,10 @@ type BuildConfig struct {
List string List string
// Whether to render it. // Whether to render it.
Render bool // Valid values: never, always, link.
// The value link means it will not be rendered, but it will get a RelPermalink/Permalink.
// Note that before 0.76.0 this was a bool, so we accept those too.
Render string
// Whether to publish its resources. These will still be published on demand, // Whether to publish its resources. These will still be published on demand,
// but enabling this can be useful if the originals (e.g. images) are // but enabling this can be useful if the originals (e.g. images) are
@ -62,7 +66,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 = Never b.List = Never
b.Render = false b.Render = Never
b.PublishResources = false b.PublishResources = false
b.set = true b.set = true
} }
@ -91,5 +95,16 @@ func DecodeBuildConfig(m interface{}) (BuildConfig, error) {
b.List = Always b.List = Always
} }
// In 0.76.0 we changed the Render from bool to a string.
switch b.Render {
case "0":
b.Render = Never
case "1":
b.Render = Always
case Always, Never, Link:
default:
b.Render = Always
}
return b, err return b, err
} }

View file

@ -31,33 +31,61 @@ func TestDecodeBuildConfig(t *testing.T) {
configTempl := ` configTempl := `
[_build] [_build]
render = true render = %s
list = %s list = %s
publishResources = true` publishResources = true`
for _, test := range []struct { for _, test := range []struct {
list interface{} args []interface{}
expect string expect BuildConfig
}{ }{
{"true", Always}, {
{"false", Never}, []interface{}{"true", "true"},
{`"always"`, Always}, BuildConfig{
{`"local"`, ListLocally}, Render: Always,
{`"asdfadf"`, Always}, List: Always,
PublishResources: true,
set: true,
}},
{[]interface{}{"true", "false"}, BuildConfig{
Render: Always,
List: Never,
PublishResources: true,
set: true,
}},
{[]interface{}{`"always"`, `"always"`}, BuildConfig{
Render: Always,
List: Always,
PublishResources: true,
set: true,
}},
{[]interface{}{`"never"`, `"never"`}, BuildConfig{
Render: Never,
List: Never,
PublishResources: true,
set: true,
}},
{[]interface{}{`"link"`, `"local"`}, BuildConfig{
Render: Link,
List: ListLocally,
PublishResources: true,
set: true,
}},
{[]interface{}{`"always"`, `"asdfadf"`}, BuildConfig{
Render: Always,
List: Always,
PublishResources: true,
set: true,
}},
} { } {
cfg, err := config.FromConfigString(fmt.Sprintf(configTempl, test.list), "toml") cfg, err := config.FromConfigString(fmt.Sprintf(configTempl, test.args...), "toml")
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
bcfg, err := DecodeBuildConfig(cfg.Get("_build")) bcfg, err := DecodeBuildConfig(cfg.Get("_build"))
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
eq := qt.CmpEquals(hqt.DeepAllowUnexported(BuildConfig{})) eq := qt.CmpEquals(hqt.DeepAllowUnexported(BuildConfig{}))
c.Assert(bcfg, eq, BuildConfig{ c.Assert(bcfg, eq, test.expect)
Render: true,
List: test.expect,
PublishResources: true,
set: true,
})
} }