2019-01-02 06:33:26 -05:00
// Copyright 2019 The Hugo Authors. All rights reserved.
2015-12-10 17:19:38 -05:00
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2019-01-02 06:33:26 -05:00
package config
2014-05-06 06:50:23 -04:00
2014-05-06 11:02:56 -04:00
import (
2020-05-27 07:50:13 -04:00
"github.com/pkg/errors"
2020-03-08 11:33:15 -04:00
"sort"
2020-03-03 02:32:02 -05:00
"strings"
2020-03-08 11:33:15 -04:00
"sync"
2020-03-03 02:32:02 -05:00
2020-03-08 11:33:15 -04:00
"github.com/gohugoio/hugo/common/types"
"github.com/gobwas/glob"
2020-03-03 02:32:02 -05:00
"github.com/gohugoio/hugo/common/herrors"
"github.com/mitchellh/mapstructure"
2014-05-06 11:02:56 -04:00
"github.com/spf13/cast"
jww "github.com/spf13/jwalterweatherman"
)
2014-05-06 06:50:23 -04:00
2020-03-03 02:32:02 -05:00
var DefaultBuild = Build {
UseResourceCacheWhen : "fallback" ,
2020-03-03 06:25:03 -05:00
WriteStats : false ,
2020-03-03 02:32:02 -05:00
}
// Build holds some build related condfiguration.
type Build struct {
UseResourceCacheWhen string // never, fallback, always. Default is fallback
2020-03-03 06:25:03 -05:00
// When enabled, will collect and write a hugo_stats.json with some build
// related aggregated data (e.g. CSS class names).
WriteStats bool
2020-10-05 07:34:14 -04:00
// Can be used to toggle off writing of the intellinsense /assets/jsconfig.js
// file.
NoJSConfigInAssets bool
2020-03-03 02:32:02 -05:00
}
func ( b Build ) UseResourceCache ( err error ) bool {
if b . UseResourceCacheWhen == "never" {
return false
}
if b . UseResourceCacheWhen == "fallback" {
return err == herrors . ErrFeatureNotAvailable
}
return true
}
func DecodeBuild ( cfg Provider ) Build {
m := cfg . GetStringMap ( "build" )
b := DefaultBuild
if m == nil {
return b
}
err := mapstructure . WeakDecode ( m , & b )
if err != nil {
return DefaultBuild
}
b . UseResourceCacheWhen = strings . ToLower ( b . UseResourceCacheWhen )
when := b . UseResourceCacheWhen
if when != "never" && when != "always" && when != "fallback" {
b . UseResourceCacheWhen = "fallback"
}
return b
}
2016-03-23 05:10:28 -04:00
// Sitemap configures the sitemap to be generated.
2014-05-06 06:50:23 -04:00
type Sitemap struct {
ChangeFreq string
2014-05-06 11:02:56 -04:00
Priority float64
2015-12-10 14:39:06 -05:00
Filename string
2014-05-06 06:50:23 -04:00
}
2019-01-02 06:33:26 -05:00
func DecodeSitemap ( prototype Sitemap , input map [ string ] interface { } ) Sitemap {
2014-05-06 11:02:56 -04:00
for key , value := range input {
switch key {
case "changefreq" :
2019-01-02 06:33:26 -05:00
prototype . ChangeFreq = cast . ToString ( value )
2014-05-06 11:02:56 -04:00
case "priority" :
2019-01-02 06:33:26 -05:00
prototype . Priority = cast . ToFloat64 ( value )
2015-12-10 14:39:06 -05:00
case "filename" :
2019-01-02 06:33:26 -05:00
prototype . Filename = cast . ToString ( value )
2014-05-06 11:02:56 -04:00
default :
jww . WARN . Printf ( "Unknown Sitemap field: %s\n" , key )
}
2014-05-06 06:50:23 -04:00
}
2014-05-06 11:02:56 -04:00
2019-01-02 06:33:26 -05:00
return prototype
2014-05-06 06:50:23 -04:00
}
2020-03-08 11:33:15 -04:00
// Config for the dev server.
type Server struct {
2020-05-27 07:50:13 -04:00
Headers [ ] Headers
Redirects [ ] Redirect
2020-03-08 11:33:15 -04:00
2020-05-27 07:50:13 -04:00
compiledInit sync . Once
compiledHeaders [ ] glob . Glob
compiledRedirects [ ] glob . Glob
2020-03-08 11:33:15 -04:00
}
2020-05-27 07:50:13 -04:00
func ( s * Server ) init ( ) {
2020-03-08 11:33:15 -04:00
s . compiledInit . Do ( func ( ) {
for _ , h := range s . Headers {
2020-05-27 07:50:13 -04:00
s . compiledHeaders = append ( s . compiledHeaders , glob . MustCompile ( h . For ) )
}
for _ , r := range s . Redirects {
s . compiledRedirects = append ( s . compiledRedirects , glob . MustCompile ( r . From ) )
2020-03-08 11:33:15 -04:00
}
} )
2020-05-27 07:50:13 -04:00
}
2020-03-08 11:33:15 -04:00
2020-05-27 07:50:13 -04:00
func ( s * Server ) MatchHeaders ( pattern string ) [ ] types . KeyValueStr {
s . init ( )
if s . compiledHeaders == nil {
2020-03-08 11:33:15 -04:00
return nil
}
var matches [ ] types . KeyValueStr
2020-05-27 07:50:13 -04:00
for i , g := range s . compiledHeaders {
2020-03-08 11:33:15 -04:00
if g . Match ( pattern ) {
h := s . Headers [ i ]
for k , v := range h . Values {
matches = append ( matches , types . KeyValueStr { Key : k , Value : cast . ToString ( v ) } )
}
}
}
sort . Slice ( matches , func ( i , j int ) bool {
return matches [ i ] . Key < matches [ j ] . Key
} )
return matches
}
2020-05-27 07:50:13 -04:00
func ( s * Server ) MatchRedirect ( pattern string ) Redirect {
s . init ( )
if s . compiledRedirects == nil {
return Redirect { }
}
pattern = strings . TrimSuffix ( pattern , "index.html" )
for i , g := range s . compiledRedirects {
redir := s . Redirects [ i ]
// No redirect to self.
if redir . To == pattern {
return Redirect { }
}
if g . Match ( pattern ) {
return redir
}
}
return Redirect { }
}
2020-03-08 11:33:15 -04:00
type Headers struct {
For string
Values map [ string ] interface { }
}
2020-05-27 07:50:13 -04:00
type Redirect struct {
From string
To string
Status int
2020-10-05 11:56:28 -04:00
Force bool
2020-05-27 07:50:13 -04:00
}
func ( r Redirect ) IsZero ( ) bool {
return r . From == ""
}
func DecodeServer ( cfg Provider ) ( * Server , error ) {
2020-03-08 11:33:15 -04:00
m := cfg . GetStringMap ( "server" )
s := & Server { }
if m == nil {
2020-05-27 07:50:13 -04:00
return s , nil
2020-03-08 11:33:15 -04:00
}
_ = mapstructure . WeakDecode ( m , s )
2020-05-27 07:50:13 -04:00
for i , redir := range s . Redirects {
// Get it in line with the Hugo server.
redir . To = strings . TrimSuffix ( redir . To , "index.html" )
if ! strings . HasPrefix ( redir . To , "https" ) && ! strings . HasSuffix ( redir . To , "/" ) {
// There are some tricky infinite loop situations when dealing
// when the target does not have a trailing slash.
// This can certainly be handled better, but not time for that now.
2020-09-19 16:00:21 -04:00
return nil , errors . 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 )
2020-05-27 07:50:13 -04:00
}
s . Redirects [ i ] = redir
}
return s , nil
2020-03-08 11:33:15 -04:00
}