hugolib: Fix freeze in invalid front matter error case

Fixes #4526
This commit is contained in:
Bjørn Erik Pedersen 2018-03-24 09:19:49 +01:00
parent e9c7b6205f
commit 93e24a03ce
No known key found for this signature in database
GPG key ID: 330E6E2BD4859D8F
4 changed files with 95 additions and 14 deletions

View file

@ -0,0 +1,42 @@
package hugolib
import (
"fmt"
"testing"
)
// https://github.com/gohugoio/hugo/issues/4526
func TestSiteBuildFailureInvalidPageMetadata(t *testing.T) {
t.Parallel()
validContentFile := `
---
title = "This is good"
---
Some content.
`
invalidContentFile := `
---
title = "PDF EPUB: Anne Bradstreet: Poems "The Prologue Summary And Analysis EBook Full Text "
---
Some content.
`
var contentFiles []string
for i := 0; i <= 30; i++ {
name := fmt.Sprintf("valid%d.md", i)
contentFiles = append(contentFiles, name, validContentFile)
if i%5 == 0 {
name = fmt.Sprintf("invalid%d.md", i)
contentFiles = append(contentFiles, name, invalidContentFile)
}
}
b := newTestSitesBuilder(t)
b.WithSimpleConfigFile().WithContent(contentFiles...)
b.CreateSites().BuildFail(BuildCfg{})
}

View file

@ -32,6 +32,8 @@ type siteContentProcessor struct {
handleContent contentHandler
ctx context.Context
// The input file bundles.
fileBundlesChan chan *bundleDir
@ -51,7 +53,28 @@ type siteContentProcessor struct {
partialBuild bool
}
func newSiteContentProcessor(baseDir string, partialBuild bool, s *Site) *siteContentProcessor {
func (s *siteContentProcessor) processBundle(b *bundleDir) {
select {
case s.fileBundlesChan <- b:
case <-s.ctx.Done():
}
}
func (s *siteContentProcessor) processSingle(fi *fileInfo) {
select {
case s.fileSinglesChan <- fi:
case <-s.ctx.Done():
}
}
func (s *siteContentProcessor) processAssets(assets []string) {
select {
case s.fileAssetsChan <- assets:
case <-s.ctx.Done():
}
}
func newSiteContentProcessor(ctx context.Context, baseDir string, partialBuild bool, s *Site) *siteContentProcessor {
numWorkers := 12
if n := runtime.NumCPU() * 3; n > numWorkers {
numWorkers = n
@ -60,6 +83,7 @@ func newSiteContentProcessor(baseDir string, partialBuild bool, s *Site) *siteCo
numWorkers = int(math.Ceil(float64(numWorkers) / float64(len(s.owner.Sites))))
return &siteContentProcessor{
ctx: ctx,
partialBuild: partialBuild,
baseDir: baseDir,
site: s,
@ -80,7 +104,7 @@ func (s *siteContentProcessor) closeInput() {
func (s *siteContentProcessor) process(ctx context.Context) error {
g1, ctx := errgroup.WithContext(ctx)
g2, _ := errgroup.WithContext(ctx)
g2, ctx := errgroup.WithContext(ctx)
// There can be only one of these per site.
g1.Go(func() error {
@ -161,12 +185,14 @@ func (s *siteContentProcessor) process(ctx context.Context) error {
})
}
if err := g2.Wait(); err != nil {
return err
}
err := g2.Wait()
close(s.pagesChan)
if err != nil {
return err
}
if err := g1.Wait(); err != nil {
return err
}

View file

@ -1281,19 +1281,19 @@ func (c *contentCaptureResultHandler) getContentProcessor(lang string) *siteCont
func (c *contentCaptureResultHandler) handleSingles(fis ...*fileInfo) {
for _, fi := range fis {
proc := c.getContentProcessor(fi.Lang())
proc.fileSinglesChan <- fi
proc.processSingle(fi)
}
}
func (c *contentCaptureResultHandler) handleBundles(d *bundleDirs) {
for _, b := range d.bundles {
proc := c.getContentProcessor(b.fi.Lang())
proc.fileBundlesChan <- b
proc.processBundle(b)
}
}
func (c *contentCaptureResultHandler) handleCopyFiles(filenames ...string) {
for _, proc := range c.contentProcessors {
proc.fileAssetsChan <- filenames
proc.processAssets(filenames)
}
}
@ -1309,7 +1309,7 @@ func (s *Site) readAndProcessContent(filenames ...string) error {
var defaultContentProcessor *siteContentProcessor
sites := s.owner.langSite()
for k, v := range sites {
proc := newSiteContentProcessor(baseDir, len(filenames) > 0, v)
proc := newSiteContentProcessor(ctx, baseDir, len(filenames) > 0, v)
contentProcessors[k] = proc
if k == defaultContentLanguage {
defaultContentProcessor = proc
@ -1337,15 +1337,18 @@ func (s *Site) readAndProcessContent(filenames ...string) error {
c := newCapturer(s.Log, sourceSpec, handler, bundleMap, baseDir, filenames...)
if err := c.capture(); err != nil {
return err
}
err1 := c.capture()
for _, proc := range contentProcessors {
proc.closeInput()
}
return g.Wait()
err2 := g.Wait()
if err1 != nil {
return err1
}
return err2
}
func (s *Site) buildSiteMeta() (err error) {

View file

@ -272,12 +272,22 @@ func (s *sitesBuilder) CreateSites() *sitesBuilder {
}
func (s *sitesBuilder) Build(cfg BuildCfg) *sitesBuilder {
return s.build(cfg, false)
}
func (s *sitesBuilder) BuildFail(cfg BuildCfg) *sitesBuilder {
return s.build(cfg, true)
}
func (s *sitesBuilder) build(cfg BuildCfg, shouldFail bool) *sitesBuilder {
if s.H == nil {
s.CreateSites()
}
err := s.H.Build(cfg)
if err != nil {
if err != nil && !shouldFail {
s.Fatalf("Build failed: %s", err)
} else if err == nil && shouldFail {
s.Fatalf("Expected error")
}
return s