hugo

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

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

commonConfig.go (4957B)

    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 config
   15 
   16 import (
   17 	"fmt"
   18 	"sort"
   19 	"strings"
   20 	"sync"
   21 
   22 	"github.com/gohugoio/hugo/common/types"
   23 
   24 	"github.com/gobwas/glob"
   25 	"github.com/gohugoio/hugo/common/herrors"
   26 	"github.com/mitchellh/mapstructure"
   27 	"github.com/spf13/cast"
   28 	jww "github.com/spf13/jwalterweatherman"
   29 )
   30 
   31 var DefaultBuild = Build{
   32 	UseResourceCacheWhen: "fallback",
   33 	WriteStats:           false,
   34 }
   35 
   36 // Build holds some build related configuration.
   37 type Build struct {
   38 	UseResourceCacheWhen string // never, fallback, always. Default is fallback
   39 
   40 	// When enabled, will collect and write a hugo_stats.json with some build
   41 	// related aggregated data (e.g. CSS class names).
   42 	WriteStats bool
   43 
   44 	// Can be used to toggle off writing of the intellinsense /assets/jsconfig.js
   45 	// file.
   46 	NoJSConfigInAssets bool
   47 }
   48 
   49 func (b Build) UseResourceCache(err error) bool {
   50 	if b.UseResourceCacheWhen == "never" {
   51 		return false
   52 	}
   53 
   54 	if b.UseResourceCacheWhen == "fallback" {
   55 		return err == herrors.ErrFeatureNotAvailable
   56 	}
   57 
   58 	return true
   59 }
   60 
   61 func DecodeBuild(cfg Provider) Build {
   62 	m := cfg.GetStringMap("build")
   63 	b := DefaultBuild
   64 	if m == nil {
   65 		return b
   66 	}
   67 
   68 	err := mapstructure.WeakDecode(m, &b)
   69 	if err != nil {
   70 		return DefaultBuild
   71 	}
   72 
   73 	b.UseResourceCacheWhen = strings.ToLower(b.UseResourceCacheWhen)
   74 	when := b.UseResourceCacheWhen
   75 	if when != "never" && when != "always" && when != "fallback" {
   76 		b.UseResourceCacheWhen = "fallback"
   77 	}
   78 
   79 	return b
   80 }
   81 
   82 // Sitemap configures the sitemap to be generated.
   83 type Sitemap struct {
   84 	ChangeFreq string
   85 	Priority   float64
   86 	Filename   string
   87 }
   88 
   89 func DecodeSitemap(prototype Sitemap, input map[string]any) Sitemap {
   90 	for key, value := range input {
   91 		switch key {
   92 		case "changefreq":
   93 			prototype.ChangeFreq = cast.ToString(value)
   94 		case "priority":
   95 			prototype.Priority = cast.ToFloat64(value)
   96 		case "filename":
   97 			prototype.Filename = cast.ToString(value)
   98 		default:
   99 			jww.WARN.Printf("Unknown Sitemap field: %s\n", key)
  100 		}
  101 	}
  102 
  103 	return prototype
  104 }
  105 
  106 // Config for the dev server.
  107 type Server struct {
  108 	Headers   []Headers
  109 	Redirects []Redirect
  110 
  111 	compiledInit      sync.Once
  112 	compiledHeaders   []glob.Glob
  113 	compiledRedirects []glob.Glob
  114 }
  115 
  116 func (s *Server) init() {
  117 	s.compiledInit.Do(func() {
  118 		for _, h := range s.Headers {
  119 			s.compiledHeaders = append(s.compiledHeaders, glob.MustCompile(h.For))
  120 		}
  121 		for _, r := range s.Redirects {
  122 			s.compiledRedirects = append(s.compiledRedirects, glob.MustCompile(r.From))
  123 		}
  124 	})
  125 }
  126 
  127 func (s *Server) MatchHeaders(pattern string) []types.KeyValueStr {
  128 	s.init()
  129 
  130 	if s.compiledHeaders == nil {
  131 		return nil
  132 	}
  133 
  134 	var matches []types.KeyValueStr
  135 
  136 	for i, g := range s.compiledHeaders {
  137 		if g.Match(pattern) {
  138 			h := s.Headers[i]
  139 			for k, v := range h.Values {
  140 				matches = append(matches, types.KeyValueStr{Key: k, Value: cast.ToString(v)})
  141 			}
  142 		}
  143 	}
  144 
  145 	sort.Slice(matches, func(i, j int) bool {
  146 		return matches[i].Key < matches[j].Key
  147 	})
  148 
  149 	return matches
  150 }
  151 
  152 func (s *Server) MatchRedirect(pattern string) Redirect {
  153 	s.init()
  154 
  155 	if s.compiledRedirects == nil {
  156 		return Redirect{}
  157 	}
  158 
  159 	pattern = strings.TrimSuffix(pattern, "index.html")
  160 
  161 	for i, g := range s.compiledRedirects {
  162 		redir := s.Redirects[i]
  163 
  164 		// No redirect to self.
  165 		if redir.To == pattern {
  166 			return Redirect{}
  167 		}
  168 
  169 		if g.Match(pattern) {
  170 			return redir
  171 		}
  172 	}
  173 
  174 	return Redirect{}
  175 }
  176 
  177 type Headers struct {
  178 	For    string
  179 	Values map[string]any
  180 }
  181 
  182 type Redirect struct {
  183 	From   string
  184 	To     string
  185 	Status int
  186 	Force  bool
  187 }
  188 
  189 func (r Redirect) IsZero() bool {
  190 	return r.From == ""
  191 }
  192 
  193 func DecodeServer(cfg Provider) (*Server, error) {
  194 	m := cfg.GetStringMap("server")
  195 	s := &Server{}
  196 	if m == nil {
  197 		return s, nil
  198 	}
  199 
  200 	_ = mapstructure.WeakDecode(m, s)
  201 
  202 	for i, redir := range s.Redirects {
  203 		// Get it in line with the Hugo server.
  204 		redir.To = strings.TrimSuffix(redir.To, "index.html")
  205 		if !strings.HasPrefix(redir.To, "https") && !strings.HasSuffix(redir.To, "/") {
  206 			// There are some tricky infinite loop situations when dealing
  207 			// when the target does not have a trailing slash.
  208 			// This can certainly be handled better, but not time for that now.
  209 			return nil, fmt.Errorf("unsupported redirect to value %q in server config; currently this must be either a remote destination or a local folder, e.g. \"/blog/\" or \"/blog/index.html\"", redir.To)
  210 		}
  211 		s.Redirects[i] = redir
  212 	}
  213 
  214 	return s, nil
  215 }