shithub: hugo

Download patch

ref: 93e24a03ce98d3212a2d49ad04739141229d0809
parent: e9c7b6205f94a7edac0e0df2cd18d1456cb26a06
author: Bjørn Erik Pedersen <[email protected]>
date: Sat Mar 24 05:19:49 EDT 2018

hugolib: Fix freeze in invalid front matter error case

Fixes #4526

--- /dev/null
+++ b/hugolib/hugo_sites_build_failures_test.go
@@ -1,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{})
+
+}
--- a/hugolib/page_bundler.go
+++ b/hugolib/page_bundler.go
@@ -32,6 +32,8 @@
 
 	handleContent contentHandler
 
+	ctx context.Context
+
 	// The input file bundles.
 	fileBundlesChan chan *bundleDir
 
@@ -51,7 +53,28 @@
 	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 @@
 	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) 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,11 +185,13 @@
 		})
 	}
 
-	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
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -1281,19 +1281,19 @@
 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 @@
 	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 @@
 
 	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) {
--- a/hugolib/testhelpers_test.go
+++ b/hugolib/testhelpers_test.go
@@ -272,12 +272,22 @@
 }
 
 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