--- /dev/null
+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{})
+
+}
handleContent contentHandler
+ ctx context.Context
+
// The input file bundles.
fileBundlesChan chan *bundleDir
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
numWorkers = int(math.Ceil(float64(numWorkers) / float64(len(s.owner.Sites))))
return &siteContentProcessor{
+ ctx: ctx,
partialBuild: partialBuild,
baseDir: baseDir,
site: s,
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 {
})
}
- 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
}
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)
}
}
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
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) {
}
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