mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
e9c7b6205f
commit
93e24a03ce
4 changed files with 95 additions and 14 deletions
42
hugolib/hugo_sites_build_failures_test.go
Normal file
42
hugolib/hugo_sites_build_failures_test.go
Normal 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{})
|
||||||
|
|
||||||
|
}
|
|
@ -32,6 +32,8 @@ type siteContentProcessor struct {
|
||||||
|
|
||||||
handleContent contentHandler
|
handleContent contentHandler
|
||||||
|
|
||||||
|
ctx context.Context
|
||||||
|
|
||||||
// The input file bundles.
|
// The input file bundles.
|
||||||
fileBundlesChan chan *bundleDir
|
fileBundlesChan chan *bundleDir
|
||||||
|
|
||||||
|
@ -51,7 +53,28 @@ type siteContentProcessor struct {
|
||||||
partialBuild bool
|
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
|
numWorkers := 12
|
||||||
if n := runtime.NumCPU() * 3; n > numWorkers {
|
if n := runtime.NumCPU() * 3; n > numWorkers {
|
||||||
numWorkers = n
|
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))))
|
numWorkers = int(math.Ceil(float64(numWorkers) / float64(len(s.owner.Sites))))
|
||||||
|
|
||||||
return &siteContentProcessor{
|
return &siteContentProcessor{
|
||||||
|
ctx: ctx,
|
||||||
partialBuild: partialBuild,
|
partialBuild: partialBuild,
|
||||||
baseDir: baseDir,
|
baseDir: baseDir,
|
||||||
site: s,
|
site: s,
|
||||||
|
@ -80,7 +104,7 @@ func (s *siteContentProcessor) closeInput() {
|
||||||
|
|
||||||
func (s *siteContentProcessor) process(ctx context.Context) error {
|
func (s *siteContentProcessor) process(ctx context.Context) error {
|
||||||
g1, ctx := errgroup.WithContext(ctx)
|
g1, ctx := errgroup.WithContext(ctx)
|
||||||
g2, _ := errgroup.WithContext(ctx)
|
g2, ctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
// There can be only one of these per site.
|
// There can be only one of these per site.
|
||||||
g1.Go(func() error {
|
g1.Go(func() error {
|
||||||
|
@ -161,12 +185,14 @@ func (s *siteContentProcessor) process(ctx context.Context) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := g2.Wait(); err != nil {
|
err := g2.Wait()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
close(s.pagesChan)
|
close(s.pagesChan)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := g1.Wait(); err != nil {
|
if err := g1.Wait(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1281,19 +1281,19 @@ func (c *contentCaptureResultHandler) getContentProcessor(lang string) *siteCont
|
||||||
func (c *contentCaptureResultHandler) handleSingles(fis ...*fileInfo) {
|
func (c *contentCaptureResultHandler) handleSingles(fis ...*fileInfo) {
|
||||||
for _, fi := range fis {
|
for _, fi := range fis {
|
||||||
proc := c.getContentProcessor(fi.Lang())
|
proc := c.getContentProcessor(fi.Lang())
|
||||||
proc.fileSinglesChan <- fi
|
proc.processSingle(fi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (c *contentCaptureResultHandler) handleBundles(d *bundleDirs) {
|
func (c *contentCaptureResultHandler) handleBundles(d *bundleDirs) {
|
||||||
for _, b := range d.bundles {
|
for _, b := range d.bundles {
|
||||||
proc := c.getContentProcessor(b.fi.Lang())
|
proc := c.getContentProcessor(b.fi.Lang())
|
||||||
proc.fileBundlesChan <- b
|
proc.processBundle(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *contentCaptureResultHandler) handleCopyFiles(filenames ...string) {
|
func (c *contentCaptureResultHandler) handleCopyFiles(filenames ...string) {
|
||||||
for _, proc := range c.contentProcessors {
|
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
|
var defaultContentProcessor *siteContentProcessor
|
||||||
sites := s.owner.langSite()
|
sites := s.owner.langSite()
|
||||||
for k, v := range sites {
|
for k, v := range sites {
|
||||||
proc := newSiteContentProcessor(baseDir, len(filenames) > 0, v)
|
proc := newSiteContentProcessor(ctx, baseDir, len(filenames) > 0, v)
|
||||||
contentProcessors[k] = proc
|
contentProcessors[k] = proc
|
||||||
if k == defaultContentLanguage {
|
if k == defaultContentLanguage {
|
||||||
defaultContentProcessor = proc
|
defaultContentProcessor = proc
|
||||||
|
@ -1337,15 +1337,18 @@ func (s *Site) readAndProcessContent(filenames ...string) error {
|
||||||
|
|
||||||
c := newCapturer(s.Log, sourceSpec, handler, bundleMap, baseDir, filenames...)
|
c := newCapturer(s.Log, sourceSpec, handler, bundleMap, baseDir, filenames...)
|
||||||
|
|
||||||
if err := c.capture(); err != nil {
|
err1 := c.capture()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, proc := range contentProcessors {
|
for _, proc := range contentProcessors {
|
||||||
proc.closeInput()
|
proc.closeInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
return g.Wait()
|
err2 := g.Wait()
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
return err2
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Site) buildSiteMeta() (err error) {
|
func (s *Site) buildSiteMeta() (err error) {
|
||||||
|
|
|
@ -272,12 +272,22 @@ func (s *sitesBuilder) CreateSites() *sitesBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) Build(cfg BuildCfg) *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 {
|
if s.H == nil {
|
||||||
s.CreateSites()
|
s.CreateSites()
|
||||||
}
|
}
|
||||||
err := s.H.Build(cfg)
|
err := s.H.Build(cfg)
|
||||||
if err != nil {
|
if err != nil && !shouldFail {
|
||||||
s.Fatalf("Build failed: %s", err)
|
s.Fatalf("Build failed: %s", err)
|
||||||
|
} else if err == nil && shouldFail {
|
||||||
|
s.Fatalf("Expected error")
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
Loading…
Reference in a new issue