From 67f6956bc6256d300cede9638d416f007a3e83b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Mon, 15 Apr 2019 12:06:12 +0200 Subject: [PATCH] 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 --- hugolib/page.go | 58 ++++++++++++++++++++----------------- hugolib/page__common.go | 5 ++-- hugolib/pagebundler_test.go | 34 ++++++++++++++++++++++ hugolib/shortcode_test.go | 14 +++++---- hugolib/site_render.go | 12 ++++---- 5 files changed, 83 insertions(+), 40 deletions(-) diff --git a/hugolib/page.go b/hugolib/page.go index 2ed828df6bd..73ed518760d 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -360,40 +360,44 @@ func (p *pageState) setPages(pages page.Pages) { p.pages = pages } -func (p *pageState) renderResources() error { - var toBeDeleted []int - - for i, r := range p.Resources() { - if _, ok := r.(page.Page); ok { - // Pages gets rendered with the owning page but we count them here. - p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Pages) - continue - } +func (p *pageState) renderResources() (err error) { + p.resourcesPublishInit.Do(func() { + var toBeDeleted []int + + for i, r := range p.Resources() { + if _, ok := r.(page.Page); ok { + // Pages gets rendered with the owning page but we count them here. + p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Pages) + continue + } - src, ok := r.(resource.Source) - if !ok { - return errors.Errorf("Resource %T does not support resource.Source", src) - } + src, ok := r.(resource.Source) + if !ok { + err = errors.Errorf("Resource %T does not support resource.Source", src) + return + } - if err := src.Publish(); err != nil { - if os.IsNotExist(err) { - // The resource has been deleted from the file system. - // This should be extremely rare, but can happen on live reload in server - // mode when the same resource is member of different page bundles. - toBeDeleted = append(toBeDeleted, i) + if err := src.Publish(); err != nil { + if os.IsNotExist(err) { + // The resource has been deleted from the file system. + // This should be extremely rare, but can happen on live reload in server + // mode when the same resource is member of different page bundles. + toBeDeleted = append(toBeDeleted, i) + } else { + 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) + 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 { - p.deleteResource(i) - } + for _, i := range toBeDeleted { + p.deleteResource(i) + } - return nil + }) + + return } func (p *pageState) deleteResource(i int) { diff --git a/hugolib/page__common.go b/hugolib/page__common.go index 5bd7223cc2d..01280bb407c 100644 --- a/hugolib/page__common.go +++ b/hugolib/page__common.go @@ -91,8 +91,9 @@ type pageCommon struct { pagesInit sync.Once // Any bundled resources - resources resource.Resources - resourcesInit sync.Once + resources resource.Resources + resourcesInit sync.Once + resourcesPublishInit sync.Once translations page.Pages allTranslations page.Pages diff --git a/hugolib/pagebundler_test.go b/hugolib/pagebundler_test.go index 870ea3de9a7..06bd641542f 100644 --- a/hugolib/pagebundler_test.go +++ b/hugolib/pagebundler_test.go @@ -896,3 +896,37 @@ TheContent. 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") + +} diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go index 3320e642c44..dd01eb5c504 100644 --- a/hugolib/shortcode_test.go +++ b/hugolib/shortcode_test.go @@ -903,6 +903,7 @@ func TestShortcodeParentResourcesOnRebuild(t *testing.T) { b.WithTemplatesAdded( "index.html", ` {{ $b := .Site.GetPage "b1" }} +b1 Content: {{ $b.Content }} {{$p := $b.Resources.GetMatch "p1*" }} Content: {{ $p.Content }} {{ $article := .Site.GetPage "blog/article" }} @@ -933,20 +934,23 @@ SHORTCODE: {{< c >}} b.Build(BuildCfg{}) - assert := func() { - b.AssertFileContent("public/index.html", - "Parent resource: logo.png: /b1/logo.png", + assert := func(matchers ...string) { + allMatchers := append(matchers, "Parent resource: logo.png: /b1/logo.png", "Article Content:

SHORTCODE: \n\n* Parent resource: logo-article.png: /blog/logo-article.png", ) + + b.AssertFileContent("public/index.html", + allMatchers..., + ) } assert() - b.EditFiles("b1/index.md", pageContent+" Edit.") + b.EditFiles("content/b1/index.md", pageContent+" Edit.") b.Build(BuildCfg{}) - assert() + assert("Edit.") } diff --git a/hugolib/site_render.go b/hugolib/site_render.go index 407061b6778..ac2316ba59e 100644 --- a/hugolib/site_render.go +++ b/hugolib/site_render.go @@ -35,6 +35,7 @@ type siteRenderContext struct { sitesOutIdx int // 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 multihost bool @@ -96,7 +97,8 @@ L: wg.Wait() close(results) - + { + } err := <-errs if err != nil { return errors.Wrap(err, "failed to render pages") @@ -130,11 +132,9 @@ func pageRenderer( continue } - if ctx.outIdx == 0 { - if err := p.renderResources(); err != nil { - s.SendError(p.errorf(err, "failed to render page resources")) - continue - } + if err := p.renderResources(); err != nil { + s.SendError(p.errorf(err, "failed to render page resources")) + continue } layouts, err := p.getLayouts()