github.com/olliephillips/hugo@v0.42.2/deps/deps.go (about)

     1  package deps
     2  
     3  import (
     4  	"io/ioutil"
     5  	"log"
     6  	"os"
     7  	"time"
     8  
     9  	"github.com/gohugoio/hugo/config"
    10  	"github.com/gohugoio/hugo/helpers"
    11  	"github.com/gohugoio/hugo/hugofs"
    12  	"github.com/gohugoio/hugo/langs"
    13  	"github.com/gohugoio/hugo/metrics"
    14  	"github.com/gohugoio/hugo/output"
    15  	"github.com/gohugoio/hugo/source"
    16  	"github.com/gohugoio/hugo/tpl"
    17  	jww "github.com/spf13/jwalterweatherman"
    18  )
    19  
    20  // Deps holds dependencies used by many.
    21  // There will be normally only one instance of deps in play
    22  // at a given time, i.e. one per Site built.
    23  type Deps struct {
    24  	// The logger to use.
    25  	Log *jww.Notepad `json:"-"`
    26  
    27  	// Used to log errors that may repeat itself many times.
    28  	DistinctErrorLog *helpers.DistinctLogger
    29  
    30  	// The templates to use. This will usually implement the full tpl.TemplateHandler.
    31  	Tmpl tpl.TemplateFinder `json:"-"`
    32  
    33  	// The file systems to use.
    34  	Fs *hugofs.Fs `json:"-"`
    35  
    36  	// The PathSpec to use
    37  	*helpers.PathSpec `json:"-"`
    38  
    39  	// The ContentSpec to use
    40  	*helpers.ContentSpec `json:"-"`
    41  
    42  	// The SourceSpec to use
    43  	SourceSpec *source.SourceSpec `json:"-"`
    44  
    45  	// The configuration to use
    46  	Cfg config.Provider `json:"-"`
    47  
    48  	// The translation func to use
    49  	Translate func(translationID string, args ...interface{}) string `json:"-"`
    50  
    51  	Language *langs.Language
    52  
    53  	// All the output formats available for the current site.
    54  	OutputFormatsConfig output.Formats
    55  
    56  	templateProvider ResourceProvider
    57  	WithTemplate     func(templ tpl.TemplateHandler) error `json:"-"`
    58  
    59  	translationProvider ResourceProvider
    60  
    61  	Metrics metrics.Provider
    62  
    63  	// Timeout is configurable in site config.
    64  	Timeout time.Duration
    65  }
    66  
    67  // ResourceProvider is used to create and refresh, and clone resources needed.
    68  type ResourceProvider interface {
    69  	Update(deps *Deps) error
    70  	Clone(deps *Deps) error
    71  }
    72  
    73  // TemplateHandler returns the used tpl.TemplateFinder as tpl.TemplateHandler.
    74  func (d *Deps) TemplateHandler() tpl.TemplateHandler {
    75  	return d.Tmpl.(tpl.TemplateHandler)
    76  }
    77  
    78  // LoadResources loads translations and templates.
    79  func (d *Deps) LoadResources() error {
    80  	// Note that the translations need to be loaded before the templates.
    81  	if err := d.translationProvider.Update(d); err != nil {
    82  		return err
    83  	}
    84  
    85  	if err := d.templateProvider.Update(d); err != nil {
    86  		return err
    87  	}
    88  
    89  	if th, ok := d.Tmpl.(tpl.TemplateHandler); ok {
    90  		th.PrintErrors()
    91  	}
    92  
    93  	return nil
    94  }
    95  
    96  // New initializes a Dep struct.
    97  // Defaults are set for nil values,
    98  // but TemplateProvider, TranslationProvider and Language are always required.
    99  func New(cfg DepsCfg) (*Deps, error) {
   100  	var (
   101  		logger = cfg.Logger
   102  		fs     = cfg.Fs
   103  	)
   104  
   105  	if cfg.TemplateProvider == nil {
   106  		panic("Must have a TemplateProvider")
   107  	}
   108  
   109  	if cfg.TranslationProvider == nil {
   110  		panic("Must have a TranslationProvider")
   111  	}
   112  
   113  	if cfg.Language == nil {
   114  		panic("Must have a Language")
   115  	}
   116  
   117  	if logger == nil {
   118  		logger = jww.NewNotepad(jww.LevelError, jww.LevelError, os.Stdout, ioutil.Discard, "", log.Ldate|log.Ltime)
   119  	}
   120  
   121  	if fs == nil {
   122  		// Default to the production file system.
   123  		fs = hugofs.NewDefault(cfg.Language)
   124  	}
   125  
   126  	ps, err := helpers.NewPathSpec(fs, cfg.Language)
   127  
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	contentSpec, err := helpers.NewContentSpec(cfg.Language)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	sp := source.NewSourceSpec(ps, fs.Source)
   138  
   139  	timeoutms := cfg.Language.GetInt("timeout")
   140  	if timeoutms <= 0 {
   141  		timeoutms = 3000
   142  	}
   143  
   144  	distinctErrorLogger := helpers.NewDistinctLogger(logger.ERROR)
   145  
   146  	d := &Deps{
   147  		Fs:                  fs,
   148  		Log:                 logger,
   149  		DistinctErrorLog:    distinctErrorLogger,
   150  		templateProvider:    cfg.TemplateProvider,
   151  		translationProvider: cfg.TranslationProvider,
   152  		WithTemplate:        cfg.WithTemplate,
   153  		PathSpec:            ps,
   154  		ContentSpec:         contentSpec,
   155  		SourceSpec:          sp,
   156  		Cfg:                 cfg.Language,
   157  		Language:            cfg.Language,
   158  		Timeout:             time.Duration(timeoutms) * time.Millisecond,
   159  	}
   160  
   161  	if cfg.Cfg.GetBool("templateMetrics") {
   162  		d.Metrics = metrics.NewProvider(cfg.Cfg.GetBool("templateMetricsHints"))
   163  	}
   164  
   165  	return d, nil
   166  }
   167  
   168  // ForLanguage creates a copy of the Deps with the language dependent
   169  // parts switched out.
   170  func (d Deps) ForLanguage(l *langs.Language) (*Deps, error) {
   171  	var err error
   172  
   173  	d.PathSpec, err = helpers.NewPathSpecWithBaseBaseFsProvided(d.Fs, l, d.BaseFs)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  
   178  	d.ContentSpec, err = helpers.NewContentSpec(l)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  
   183  	d.Cfg = l
   184  	d.Language = l
   185  
   186  	if err := d.translationProvider.Clone(&d); err != nil {
   187  		return nil, err
   188  	}
   189  
   190  	if err := d.templateProvider.Clone(&d); err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	return &d, nil
   195  
   196  }
   197  
   198  // DepsCfg contains configuration options that can be used to configure Hugo
   199  // on a global level, i.e. logging etc.
   200  // Nil values will be given default values.
   201  type DepsCfg struct {
   202  
   203  	// The Logger to use.
   204  	Logger *jww.Notepad
   205  
   206  	// The file systems to use
   207  	Fs *hugofs.Fs
   208  
   209  	// The language to use.
   210  	Language *langs.Language
   211  
   212  	// The configuration to use.
   213  	Cfg config.Provider
   214  
   215  	// Template handling.
   216  	TemplateProvider ResourceProvider
   217  	WithTemplate     func(templ tpl.TemplateHandler) error
   218  
   219  	// i18n handling.
   220  	TranslationProvider ResourceProvider
   221  
   222  	// Whether we are in running (server) mode
   223  	Running bool
   224  }