github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/hugolib/pages_process.go (about)

     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  	"github.com/pkg/errors"
    26  	"golang.org/x/sync/errgroup"
    27  
    28  	"github.com/gohugoio/hugo/common/herrors"
    29  	"github.com/gohugoio/hugo/hugofs"
    30  )
    31  
    32  func newPagesProcessor(h *HugoSites, sp *source.SourceSpec) *pagesProcessor {
    33  	procs := make(map[string]pagesCollectorProcessorProvider)
    34  	for _, s := range h.Sites {
    35  		procs[s.Lang()] = &sitePagesProcessor{
    36  			m:           s.pageMap,
    37  			errorSender: s.h,
    38  			itemChan:    make(chan interface{}, config.GetNumWorkerMultiplier()*2),
    39  		}
    40  	}
    41  	return &pagesProcessor{
    42  		procs: procs,
    43  	}
    44  }
    45  
    46  type pagesCollectorProcessorProvider interface {
    47  	Process(item interface{}) 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 interface{}) 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 interface{}) 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  	itemChan  chan interface{}
   119  	itemGroup *errgroup.Group
   120  }
   121  
   122  func (p *sitePagesProcessor) Process(item interface{}) error {
   123  	p.itemChan <- item
   124  	return nil
   125  }
   126  
   127  func (p *sitePagesProcessor) Start(ctx context.Context) context.Context {
   128  	p.itemGroup, ctx = errgroup.WithContext(ctx)
   129  	p.itemGroup.Go(func() error {
   130  		for item := range p.itemChan {
   131  			if err := p.doProcess(item); err != nil {
   132  				return err
   133  			}
   134  		}
   135  		return nil
   136  	})
   137  	return ctx
   138  }
   139  
   140  func (p *sitePagesProcessor) Wait() error {
   141  	close(p.itemChan)
   142  	return p.itemGroup.Wait()
   143  }
   144  
   145  func (p *sitePagesProcessor) copyFile(fim hugofs.FileMetaInfo) error {
   146  	meta := fim.Meta()
   147  	f, err := meta.Open()
   148  	if err != nil {
   149  		return errors.Wrap(err, "copyFile: failed to open")
   150  	}
   151  
   152  	s := p.m.s
   153  
   154  	target := filepath.Join(s.PathSpec.GetTargetLanguageBasePath(), meta.Path)
   155  
   156  	defer f.Close()
   157  
   158  	return s.publish(&s.PathSpec.ProcessingStats.Files, target, f)
   159  }
   160  
   161  func (p *sitePagesProcessor) doProcess(item interface{}) error {
   162  	m := p.m
   163  	switch v := item.(type) {
   164  	case *fileinfoBundle:
   165  		if err := m.AddFilesBundle(v.header, v.resources...); err != nil {
   166  			return err
   167  		}
   168  	case hugofs.FileMetaInfo:
   169  		if p.shouldSkip(v) {
   170  			return nil
   171  		}
   172  		meta := v.Meta()
   173  
   174  		classifier := meta.Classifier
   175  		switch classifier {
   176  		case files.ContentClassContent:
   177  			if err := m.AddFilesBundle(v); err != nil {
   178  				return err
   179  			}
   180  		case files.ContentClassFile:
   181  			if err := p.copyFile(v); err != nil {
   182  				return err
   183  			}
   184  		default:
   185  			panic(fmt.Sprintf("invalid classifier: %q", classifier))
   186  		}
   187  	default:
   188  		panic(fmt.Sprintf("unrecognized item type in Process: %T", item))
   189  	}
   190  	return nil
   191  }
   192  
   193  func (p *sitePagesProcessor) shouldSkip(fim hugofs.FileMetaInfo) bool {
   194  	// TODO(ep) unify
   195  	return p.m.s.SourceSpec.DisabledLanguages[fim.Meta().Lang]
   196  }