hugolib: Fix bundle resource publishing when multiple output formats

The faulty logic published the bundled resources for the "first output" format.

This worked most of the time, but since the output formats list is sorted,
any output format only used for some of the pages (e.g. CSS) would not work properly.

Fixes #5858
This commit is contained in:
Bjørn Erik Pedersen 2019-04-15 12:06:12 +02:00
parent b799b12f4a
commit 49d0a82641
5 changed files with 83 additions and 41 deletions

View file

@ -360,40 +360,44 @@ func (p *pageState) setPages(pages page.Pages) {
p.pages = pages p.pages = pages
} }
func (p *pageState) renderResources() error { func (p *pageState) renderResources() (err error) {
var toBeDeleted []int p.resourcesPublishInit.Do(func() {
var toBeDeleted []int
for i, r := range p.Resources() { for i, r := range p.Resources() {
if _, ok := r.(page.Page); ok { if _, ok := r.(page.Page); ok {
// Pages gets rendered with the owning page but we count them here. // Pages gets rendered with the owning page but we count them here.
p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Pages) p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Pages)
continue continue
} }
src, ok := r.(resource.Source) src, ok := r.(resource.Source)
if !ok { if !ok {
return errors.Errorf("Resource %T does not support resource.Source", src) err = errors.Errorf("Resource %T does not support resource.Source", src)
} return
}
if err := src.Publish(); err != nil {
if os.IsNotExist(err) { if err := src.Publish(); err != nil {
// The resource has been deleted from the file system. if os.IsNotExist(err) {
// This should be extremely rare, but can happen on live reload in server // The resource has been deleted from the file system.
// mode when the same resource is member of different page bundles. // This should be extremely rare, but can happen on live reload in server
toBeDeleted = append(toBeDeleted, i) // mode when the same resource is member of different page bundles.
} else { toBeDeleted = append(toBeDeleted, i)
p.s.Log.ERROR.Printf("Failed to publish Resource for page %q: %s", p.pathOrTitle(), err) } else {
p.s.Log.ERROR.Printf("Failed to publish Resource for page %q: %s", p.pathOrTitle(), err)
}
} else {
p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Files)
} }
} else {
p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Files)
} }
}
for _, i := range toBeDeleted { for _, i := range toBeDeleted {
p.deleteResource(i) p.deleteResource(i)
} }
return nil })
return
} }
func (p *pageState) deleteResource(i int) { func (p *pageState) deleteResource(i int) {

View file

@ -91,8 +91,9 @@ type pageCommon struct {
pagesInit sync.Once pagesInit sync.Once
// Any bundled resources // Any bundled resources
resources resource.Resources resources resource.Resources
resourcesInit sync.Once resourcesInit sync.Once
resourcesPublishInit sync.Once
translations page.Pages translations page.Pages
allTranslations page.Pages allTranslations page.Pages

View file

@ -896,3 +896,37 @@ TheContent.
return ps, clean, workDir return ps, clean, workDir
} }
// https://github.com/gohugoio/hugo/issues/5858
func TestBundledResourcesWhenMultipleOutputFormats(t *testing.T) {
t.Parallel()
b := newTestSitesBuilder(t).Running().WithConfigFile("toml", `
baseURL = "https://example.org"
[outputs]
# This looks odd, but it triggers the behaviour in #5858
# The total output formats list gets sorted, so CSS before HTML.
home = [ "CSS" ]
`)
b.WithContent("mybundle/index.md", `
---
title: Page
date: 2017-01-15
---
`,
"mybundle/data.json", "MyData",
)
b.CreateSites().Build(BuildCfg{})
b.AssertFileContent("public/mybundle/data.json", "MyData")
// Change the bundled JSON file and make sure it gets republished.
b.EditFiles("content/mybundle/data.json", "My changed data")
b.Build(BuildCfg{})
b.AssertFileContent("public/mybundle/data.json", "My changed data")
}

View file

@ -903,6 +903,7 @@ func TestShortcodeParentResourcesOnRebuild(t *testing.T) {
b.WithTemplatesAdded( b.WithTemplatesAdded(
"index.html", ` "index.html", `
{{ $b := .Site.GetPage "b1" }} {{ $b := .Site.GetPage "b1" }}
b1 Content: {{ $b.Content }}
{{$p := $b.Resources.GetMatch "p1*" }} {{$p := $b.Resources.GetMatch "p1*" }}
Content: {{ $p.Content }} Content: {{ $p.Content }}
{{ $article := .Site.GetPage "blog/article" }} {{ $article := .Site.GetPage "blog/article" }}
@ -933,20 +934,23 @@ SHORTCODE: {{< c >}}
b.Build(BuildCfg{}) b.Build(BuildCfg{})
assert := func() { assert := func(matchers ...string) {
b.AssertFileContent("public/index.html", allMatchers := append(matchers, "Parent resource: logo.png: /b1/logo.png",
"Parent resource: logo.png: /b1/logo.png",
"Article Content: <p>SHORTCODE: \n\n* Parent resource: logo-article.png: /blog/logo-article.png", "Article Content: <p>SHORTCODE: \n\n* Parent resource: logo-article.png: /blog/logo-article.png",
) )
b.AssertFileContent("public/index.html",
allMatchers...,
)
} }
assert() assert()
b.EditFiles("b1/index.md", pageContent+" Edit.") b.EditFiles("content/b1/index.md", pageContent+" Edit.")
b.Build(BuildCfg{}) b.Build(BuildCfg{})
assert() assert("Edit.")
} }

View file

@ -35,6 +35,7 @@ type siteRenderContext struct {
sitesOutIdx int sitesOutIdx int
// Zero based index of the output formats configured within a Site. // Zero based index of the output formats configured within a Site.
// Note that these outputs are sorted, so CSS will come before HTML.
outIdx int outIdx int
multihost bool multihost bool
@ -130,11 +131,9 @@ func pageRenderer(
continue continue
} }
if ctx.outIdx == 0 { if err := p.renderResources(); err != nil {
if err := p.renderResources(); err != nil { s.SendError(p.errorf(err, "failed to render page resources"))
s.SendError(p.errorf(err, "failed to render page resources")) continue
continue
}
} }
layouts, err := p.getLayouts() layouts, err := p.getLayouts()