hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

pages_process.go (4810B)

    1 // Copyright 2019 The Hugo Authors. All rights reserved.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 // http://www.apache.org/licenses/LICENSE-2.0
    7 //
    8 // Unless required by applicable law or agreed to in writing, software
    9 // distributed under the License is distributed on an "AS IS" BASIS,
   10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   11 // See the License for the specific language governing permissions and
   12 // limitations under the License.
   13 
   14 package hugolib
   15 
   16 import (
   17 	"context"
   18 	"fmt"
   19 	"path/filepath"
   20 
   21 	"github.com/gohugoio/hugo/config"
   22 	"github.com/gohugoio/hugo/source"
   23 
   24 	"github.com/gohugoio/hugo/hugofs/files"
   25 	"golang.org/x/sync/errgroup"
   26 
   27 	"github.com/gohugoio/hugo/common/herrors"
   28 	"github.com/gohugoio/hugo/hugofs"
   29 )
   30 
   31 func newPagesProcessor(h *HugoSites, sp *source.SourceSpec) *pagesProcessor {
   32 	procs := make(map[string]pagesCollectorProcessorProvider)
   33 	for _, s := range h.Sites {
   34 		procs[s.Lang()] = &sitePagesProcessor{
   35 			m:                  s.pageMap,
   36 			errorSender:        s.h,
   37 			itemChan:           make(chan interface{}, config.GetNumWorkerMultiplier()*2),
   38 			renderStaticToDisk: h.Cfg.GetBool("renderStaticToDisk"),
   39 		}
   40 	}
   41 	return &pagesProcessor{
   42 		procs: procs,
   43 	}
   44 }
   45 
   46 type pagesCollectorProcessorProvider interface {
   47 	Process(item any) error
   48 	Start(ctx context.Context) context.Context
   49 	Wait() error
   50 }
   51 
   52 type pagesProcessor struct {
   53 	// Per language/Site
   54 	procs map[string]pagesCollectorProcessorProvider
   55 }
   56 
   57 func (proc *pagesProcessor) Process(item any) error {
   58 	switch v := item.(type) {
   59 	// Page bundles mapped to their language.
   60 	case pageBundles:
   61 		for _, vv := range v {
   62 			proc.getProcFromFi(vv.header).Process(vv)
   63 		}
   64 	case hugofs.FileMetaInfo:
   65 		proc.getProcFromFi(v).Process(v)
   66 	default:
   67 		panic(fmt.Sprintf("unrecognized item type in Process: %T", item))
   68 
   69 	}
   70 
   71 	return nil
   72 }
   73 
   74 func (proc *pagesProcessor) Start(ctx context.Context) context.Context {
   75 	for _, p := range proc.procs {
   76 		ctx = p.Start(ctx)
   77 	}
   78 	return ctx
   79 }
   80 
   81 func (proc *pagesProcessor) Wait() error {
   82 	var err error
   83 	for _, p := range proc.procs {
   84 		if e := p.Wait(); e != nil {
   85 			err = e
   86 		}
   87 	}
   88 	return err
   89 }
   90 
   91 func (proc *pagesProcessor) getProcFromFi(fi hugofs.FileMetaInfo) pagesCollectorProcessorProvider {
   92 	if p, found := proc.procs[fi.Meta().Lang]; found {
   93 		return p
   94 	}
   95 	return defaultPageProcessor
   96 }
   97 
   98 type nopPageProcessor int
   99 
  100 func (nopPageProcessor) Process(item any) error {
  101 	return nil
  102 }
  103 
  104 func (nopPageProcessor) Start(ctx context.Context) context.Context {
  105 	return context.Background()
  106 }
  107 
  108 func (nopPageProcessor) Wait() error {
  109 	return nil
  110 }
  111 
  112 var defaultPageProcessor = new(nopPageProcessor)
  113 
  114 type sitePagesProcessor struct {
  115 	m           *pageMap
  116 	errorSender herrors.ErrorSender
  117 
  118 	ctx       context.Context
  119 	itemChan  chan any
  120 	itemGroup *errgroup.Group
  121 
  122 	renderStaticToDisk bool
  123 }
  124 
  125 func (p *sitePagesProcessor) Process(item any) error {
  126 	select {
  127 	case <-p.ctx.Done():
  128 		return nil
  129 	default:
  130 		p.itemChan <- item
  131 	}
  132 	return nil
  133 }
  134 
  135 func (p *sitePagesProcessor) Start(ctx context.Context) context.Context {
  136 	p.itemGroup, ctx = errgroup.WithContext(ctx)
  137 	p.ctx = ctx
  138 	p.itemGroup.Go(func() error {
  139 		for item := range p.itemChan {
  140 			if err := p.doProcess(item); err != nil {
  141 				return err
  142 			}
  143 		}
  144 		return nil
  145 	})
  146 	return ctx
  147 }
  148 
  149 func (p *sitePagesProcessor) Wait() error {
  150 	close(p.itemChan)
  151 	return p.itemGroup.Wait()
  152 }
  153 
  154 func (p *sitePagesProcessor) copyFile(fim hugofs.FileMetaInfo) error {
  155 	meta := fim.Meta()
  156 	f, err := meta.Open()
  157 	if err != nil {
  158 		return fmt.Errorf("copyFile: failed to open: %w", err)
  159 	}
  160 
  161 	s := p.m.s
  162 
  163 	target := filepath.Join(s.PathSpec.GetTargetLanguageBasePath(), meta.Path)
  164 
  165 	defer f.Close()
  166 
  167 	fs := s.PublishFs
  168 	if p.renderStaticToDisk {
  169 		fs = s.PublishFsStatic
  170 	}
  171 
  172 	return s.publish(&s.PathSpec.ProcessingStats.Files, target, f, fs)
  173 }
  174 
  175 func (p *sitePagesProcessor) doProcess(item any) error {
  176 	m := p.m
  177 	switch v := item.(type) {
  178 	case *fileinfoBundle:
  179 		if err := m.AddFilesBundle(v.header, v.resources...); err != nil {
  180 			return err
  181 		}
  182 	case hugofs.FileMetaInfo:
  183 		if p.shouldSkip(v) {
  184 			return nil
  185 		}
  186 		meta := v.Meta()
  187 
  188 		classifier := meta.Classifier
  189 		switch classifier {
  190 		case files.ContentClassContent:
  191 			if err := m.AddFilesBundle(v); err != nil {
  192 				return err
  193 			}
  194 		case files.ContentClassFile:
  195 			if err := p.copyFile(v); err != nil {
  196 				return err
  197 			}
  198 		default:
  199 			panic(fmt.Sprintf("invalid classifier: %q", classifier))
  200 		}
  201 	default:
  202 		panic(fmt.Sprintf("unrecognized item type in Process: %T", item))
  203 	}
  204 	return nil
  205 }
  206 
  207 func (p *sitePagesProcessor) shouldSkip(fim hugofs.FileMetaInfo) bool {
  208 	// TODO(ep) unify
  209 	return p.m.s.SourceSpec.DisabledLanguages[fim.Meta().Lang]
  210 }