Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gohugoio/hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2016-10-24 14:45:30 +0300
committerGitHub <noreply@github.com>2016-10-24 14:45:30 +0300
commita10b2cd372798c4e4b862f0ec03010d2aea2ff1e (patch)
treef768c420aac0008e4d118709e13fda278a7588c5 /helpers
parentdffd7da07c3fb198acfa6c4664b53132c4cabe55 (diff)
Avoid reading from Viper for path and URL funcs
The gain, given the "real sites benchmark" below, is obvious: ``` benchmark old ns/op new ns/op delta BenchmarkHugo-4 14497594101 13084156335 -9.75% benchmark old allocs new allocs delta BenchmarkHugo-4 57404335 48282002 -15.89% benchmark old bytes new bytes delta BenchmarkHugo-4 9933505624 9721984424 -2.13% ``` Fixes #2495
Diffstat (limited to 'helpers')
-rw-r--r--helpers/configProvider.go39
-rw-r--r--helpers/language.go21
-rw-r--r--helpers/language_test.go32
-rw-r--r--helpers/path.go16
-rw-r--r--helpers/path_test.go18
-rw-r--r--helpers/pathspec.go54
-rw-r--r--helpers/pathspec_test.go45
-rw-r--r--helpers/url.go28
-rw-r--r--helpers/url_test.go12
9 files changed, 234 insertions, 31 deletions
diff --git a/helpers/configProvider.go b/helpers/configProvider.go
index 35500f6de..a631ea63d 100644
--- a/helpers/configProvider.go
+++ b/helpers/configProvider.go
@@ -21,16 +21,55 @@ import (
"github.com/spf13/viper"
)
+// A cached version of the current ConfigProvider (language) and relatives. These globals
+// are unfortunate, but we still have some places that needs this that does
+// not have access to the site configuration.
+// These values will be set on initialization when rendering a new language.
+//
+// TODO(bep) Get rid of these.
+var (
+ currentConfigProvider ConfigProvider
+ currentPathSpec *PathSpec
+)
+
// ConfigProvider provides the configuration settings for Hugo.
type ConfigProvider interface {
GetString(key string) string
GetInt(key string) int
+ GetBool(key string) bool
GetStringMap(key string) map[string]interface{}
GetStringMapString(key string) map[string]string
+ Get(key string) interface{}
}
// Config returns the currently active Hugo config. This will be set
// per site (language) rendered.
func Config() ConfigProvider {
+ if currentConfigProvider != nil {
+ return currentConfigProvider
+ }
+ // Some tests rely on this. We will fix that, eventually.
return viper.Get("CurrentContentLanguage").(ConfigProvider)
}
+
+// CurrentPathSpec returns the current PathSpec.
+// If it is not set, a new will be created based in the currently active Hugo config.
+func CurrentPathSpec() *PathSpec {
+ if currentPathSpec != nil {
+ return currentPathSpec
+ }
+ // Some tests rely on this. We will fix that, eventually.
+ return NewPathSpecFromConfig(Config())
+}
+
+// InitConfigProviderForCurrentContentLanguage does what it says.
+func InitConfigProviderForCurrentContentLanguage() {
+ currentConfigProvider = viper.Get("CurrentContentLanguage").(ConfigProvider)
+ currentPathSpec = NewPathSpecFromConfig(currentConfigProvider)
+}
+
+// ResetConfigProvider is used in tests.
+func ResetConfigProvider() {
+ currentConfigProvider = nil
+ currentPathSpec = nil
+}
diff --git a/helpers/language.go b/helpers/language.go
index 9ebec5a65..0a1affd18 100644
--- a/helpers/language.go
+++ b/helpers/language.go
@@ -23,6 +23,19 @@ import (
"github.com/spf13/viper"
)
+// These are the settings that should only be looked up in the global Viper
+// config and not per language.
+// This list may not be complete, but contains only settings that we know
+// will be looked up in both.
+// This isn't perfect, but it is ultimately the user who shoots him/herself in
+// the foot.
+// See the pathSpec.
+var globalOnlySettings = map[string]bool{
+ strings.ToLower("defaultContentLanguageInSubdir"): true,
+ strings.ToLower("defaultContentLanguage"): true,
+ strings.ToLower("multilingual"): true,
+}
+
type Language struct {
Lang string
LanguageName string
@@ -81,7 +94,7 @@ func (l *Language) Params() map[string]interface{} {
}
func (l *Language) SetParam(k string, v interface{}) {
- l.params[k] = v
+ l.params[strings.ToLower(k)] = v
}
func (l *Language) GetBool(key string) bool { return cast.ToBool(l.Get(key)) }
@@ -101,8 +114,10 @@ func (l *Language) Get(key string) interface{} {
panic("language not set")
}
key = strings.ToLower(key)
- if v, ok := l.params[key]; ok {
- return v
+ if !globalOnlySettings[key] {
+ if v, ok := l.params[key]; ok {
+ return v
+ }
}
return viper.Get(key)
}
diff --git a/helpers/language_test.go b/helpers/language_test.go
new file mode 100644
index 000000000..f812d26a2
--- /dev/null
+++ b/helpers/language_test.go
@@ -0,0 +1,32 @@
+// Copyright 2016-present The Hugo Authors. All rights reserved.
+//
+// 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.
+
+package helpers
+
+import (
+ "testing"
+
+ "github.com/spf13/viper"
+ "github.com/stretchr/testify/require"
+)
+
+func TestGetGlobalOnlySetting(t *testing.T) {
+ lang := NewDefaultLanguage()
+ lang.SetParam("defaultContentLanguageInSubdir", false)
+ lang.SetParam("paginatePath", "side")
+ viper.Set("defaultContentLanguageInSubdir", true)
+ viper.Set("paginatePath", "page")
+
+ require.True(t, lang.GetBool("defaultContentLanguageInSubdir"))
+ require.Equal(t, "side", lang.GetString("paginatePath"))
+}
diff --git a/helpers/path.go b/helpers/path.go
index b8f642470..cf49858ee 100644
--- a/helpers/path.go
+++ b/helpers/path.go
@@ -75,16 +75,16 @@ var fpb filepathBridge
// It does so by creating a Unicode-sanitized string, with the spaces replaced,
// whilst preserving the original casing of the string.
// E.g. Social Media -> Social-Media
-func MakePath(s string) string {
- return UnicodeSanitize(strings.Replace(strings.TrimSpace(s), " ", "-", -1))
+func (p *PathSpec) MakePath(s string) string {
+ return p.UnicodeSanitize(strings.Replace(strings.TrimSpace(s), " ", "-", -1))
}
// MakePathSanitized creates a Unicode-sanitized string, with the spaces replaced
-func MakePathSanitized(s string) string {
- if viper.GetBool("DisablePathToLower") {
- return MakePath(s)
+func (p *PathSpec) MakePathSanitized(s string) string {
+ if p.disablePathToLower {
+ return p.MakePath(s)
}
- return strings.ToLower(MakePath(s))
+ return strings.ToLower(p.MakePath(s))
}
// MakeTitle converts the path given to a suitable title, trimming whitespace
@@ -110,7 +110,7 @@ func ishex(c rune) bool {
// a predefined set of special Unicode characters.
// If RemovePathAccents configuration flag is enabled, Uniccode accents
// are also removed.
-func UnicodeSanitize(s string) string {
+func (p *PathSpec) UnicodeSanitize(s string) string {
source := []rune(s)
target := make([]rune, 0, len(source))
@@ -124,7 +124,7 @@ func UnicodeSanitize(s string) string {
var result string
- if viper.GetBool("RemovePathAccents") {
+ if p.removePathAccents {
// remove accents - see https://blog.golang.org/normalization
t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
result, _, _ = transform.String(t, string(target))
diff --git a/helpers/path_test.go b/helpers/path_test.go
index cbdcd8da2..ef0c16505 100644
--- a/helpers/path_test.go
+++ b/helpers/path_test.go
@@ -33,9 +33,14 @@ import (
"github.com/spf13/viper"
)
+func initCommonTestConfig() {
+ viper.Set("CurrentContentLanguage", NewLanguage("en"))
+}
+
func TestMakePath(t *testing.T) {
viper.Reset()
defer viper.Reset()
+ initCommonTestConfig()
tests := []struct {
input string
@@ -57,7 +62,8 @@ func TestMakePath(t *testing.T) {
for _, test := range tests {
viper.Set("RemovePathAccents", test.removeAccents)
- output := MakePath(test.input)
+ p := NewPathSpecFromConfig(viper.GetViper())
+ output := p.MakePath(test.input)
if output != test.expected {
t.Errorf("Expected %#v, got %#v\n", test.expected, output)
}
@@ -67,6 +73,9 @@ func TestMakePath(t *testing.T) {
func TestMakePathSanitized(t *testing.T) {
viper.Reset()
defer viper.Reset()
+ initCommonTestConfig()
+
+ p := NewPathSpecFromConfig(viper.GetViper())
tests := []struct {
input string
@@ -81,7 +90,7 @@ func TestMakePathSanitized(t *testing.T) {
}
for _, test := range tests {
- output := MakePathSanitized(test.input)
+ output := p.MakePathSanitized(test.input)
if output != test.expected {
t.Errorf("Expected %#v, got %#v\n", test.expected, output)
}
@@ -91,7 +100,10 @@ func TestMakePathSanitized(t *testing.T) {
func TestMakePathSanitizedDisablePathToLower(t *testing.T) {
viper.Reset()
defer viper.Reset()
+
+ initCommonTestConfig()
viper.Set("DisablePathToLower", true)
+ p := NewPathSpecFromConfig(viper.GetViper())
tests := []struct {
input string
@@ -106,7 +118,7 @@ func TestMakePathSanitizedDisablePathToLower(t *testing.T) {
}
for _, test := range tests {
- output := MakePathSanitized(test.input)
+ output := p.MakePathSanitized(test.input)
if output != test.expected {
t.Errorf("Expected %#v, got %#v\n", test.expected, output)
}
diff --git a/helpers/pathspec.go b/helpers/pathspec.go
new file mode 100644
index 000000000..4c578cdf7
--- /dev/null
+++ b/helpers/pathspec.go
@@ -0,0 +1,54 @@
+// Copyright 2016-present The Hugo Authors. All rights reserved.
+//
+// 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.
+
+package helpers
+
+// PathSpec holds methods that decides how paths in URLs and files in Hugo should look like.
+type PathSpec struct {
+ disablePathToLower bool
+ removePathAccents bool
+ uglyURLs bool
+ canonifyURLs bool
+
+ currentContentLanguage *Language
+
+ // pagination path handling
+ paginatePath string
+
+ // The PathSpec looks up its config settings in both the current language
+ // and then in the global Viper config.
+ // Some settings, the settings listed below, does not make sense to be set
+ // on per-language-basis. We have no good way of protecting against this
+ // other than a "white-list". See language.go.
+ defaultContentLanguageInSubdir bool
+ defaultContentLanguage string
+ multilingual bool
+}
+
+func NewPathSpecFromConfig(config ConfigProvider) *PathSpec {
+ return &PathSpec{
+ disablePathToLower: config.GetBool("disablePathToLower"),
+ removePathAccents: config.GetBool("removePathAccents"),
+ uglyURLs: config.GetBool("uglyURLs"),
+ canonifyURLs: config.GetBool("canonifyURLs"),
+ multilingual: config.GetBool("multilingual"),
+ defaultContentLanguageInSubdir: config.GetBool("defaultContentLanguageInSubdir"),
+ defaultContentLanguage: config.GetString("defaultContentLanguage"),
+ currentContentLanguage: config.Get("currentContentLanguage").(*Language),
+ paginatePath: config.GetString("paginatePath"),
+ }
+}
+
+func (p *PathSpec) PaginatePath() string {
+ return p.paginatePath
+}
diff --git a/helpers/pathspec_test.go b/helpers/pathspec_test.go
new file mode 100644
index 000000000..9cd0af80e
--- /dev/null
+++ b/helpers/pathspec_test.go
@@ -0,0 +1,45 @@
+// Copyright 2016-present The Hugo Authors. All rights reserved.
+//
+// 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.
+
+package helpers
+
+import (
+ "testing"
+
+ "github.com/spf13/viper"
+ "github.com/stretchr/testify/require"
+)
+
+func TestNewPathSpecFromConfig(t *testing.T) {
+ viper.Set("disablePathToLower", true)
+ viper.Set("removePathAccents", true)
+ viper.Set("uglyURLs", true)
+ viper.Set("multilingual", true)
+ viper.Set("defaultContentLanguageInSubdir", true)
+ viper.Set("defaultContentLanguage", "no")
+ viper.Set("currentContentLanguage", NewLanguage("no"))
+ viper.Set("canonifyURLs", true)
+ viper.Set("paginatePath", "side")
+
+ pathSpec := NewPathSpecFromConfig(viper.GetViper())
+
+ require.True(t, pathSpec.canonifyURLs)
+ require.True(t, pathSpec.defaultContentLanguageInSubdir)
+ require.True(t, pathSpec.disablePathToLower)
+ require.True(t, pathSpec.multilingual)
+ require.True(t, pathSpec.removePathAccents)
+ require.True(t, pathSpec.uglyURLs)
+ require.Equal(t, "no", pathSpec.defaultContentLanguage)
+ require.Equal(t, "no", pathSpec.currentContentLanguage.Lang)
+ require.Equal(t, "side", pathSpec.paginatePath)
+}
diff --git a/helpers/url.go b/helpers/url.go
index 49f670da2..ffb0ba234 100644
--- a/helpers/url.go
+++ b/helpers/url.go
@@ -101,8 +101,8 @@ func SanitizeURLKeepTrailingSlash(in string) string {
// Example:
// uri: Vim (text editor)
// urlize: vim-text-editor
-func URLize(uri string) string {
- sanitized := MakePathSanitized(uri)
+func (p *PathSpec) URLize(uri string) string {
+ sanitized := p.MakePathSanitized(uri)
// escape unicode letters
parsedURI, err := url.Parse(sanitized)
@@ -147,7 +147,7 @@ func MakePermalink(host, plink string) *url.URL {
}
// AbsURL creates a absolute URL from the relative path given and the BaseURL set in config.
-func AbsURL(in string, addLanguage bool) string {
+func (p *PathSpec) AbsURL(in string, addLanguage bool) string {
url, err := url.Parse(in)
if err != nil {
return in
@@ -168,7 +168,7 @@ func AbsURL(in string, addLanguage bool) string {
}
if addLanguage {
- prefix := getLanguagePrefix()
+ prefix := p.getLanguagePrefix()
if prefix != "" {
hasPrefix := false
// avoid adding language prefix if already present
@@ -191,15 +191,15 @@ func AbsURL(in string, addLanguage bool) string {
return MakePermalink(baseURL, in).String()
}
-func getLanguagePrefix() string {
- if !viper.GetBool("Multilingual") {
+func (p *PathSpec) getLanguagePrefix() string {
+ if !p.multilingual {
return ""
}
- defaultLang := viper.GetString("DefaultContentLanguage")
- defaultInSubDir := viper.GetBool("DefaultContentLanguageInSubdir")
+ defaultLang := p.defaultContentLanguage
+ defaultInSubDir := p.defaultContentLanguageInSubdir
- currentLang := viper.Get("CurrentContentLanguage").(*Language).Lang
+ currentLang := p.currentContentLanguage.Lang
if currentLang == "" || (currentLang == defaultLang && !defaultInSubDir) {
return ""
}
@@ -218,9 +218,9 @@ func IsAbsURL(path string) bool {
// RelURL creates a URL relative to the BaseURL root.
// Note: The result URL will not include the context root if canonifyURLs is enabled.
-func RelURL(in string, addLanguage bool) string {
+func (p *PathSpec) RelURL(in string, addLanguage bool) string {
baseURL := viper.GetString("BaseURL")
- canonifyURLs := viper.GetBool("canonifyURLs")
+ canonifyURLs := p.canonifyURLs
if (!strings.HasPrefix(in, baseURL) && strings.HasPrefix(in, "http")) || strings.HasPrefix(in, "//") {
return in
}
@@ -232,7 +232,7 @@ func RelURL(in string, addLanguage bool) string {
}
if addLanguage {
- prefix := getLanguagePrefix()
+ prefix := p.getLanguagePrefix()
if prefix != "" {
hasPrefix := false
// avoid adding language prefix if already present
@@ -288,8 +288,8 @@ func AddContextRoot(baseURL, relativePath string) string {
return newPath
}
-func URLizeAndPrep(in string) string {
- return URLPrep(viper.GetBool("UglyURLs"), URLize(in))
+func (p *PathSpec) URLizeAndPrep(in string) string {
+ return URLPrep(p.uglyURLs, p.URLize(in))
}
func URLPrep(ugly bool, in string) string {
diff --git a/helpers/url_test.go b/helpers/url_test.go
index 2cf93b859..5394e9573 100644
--- a/helpers/url_test.go
+++ b/helpers/url_test.go
@@ -24,6 +24,10 @@ import (
)
func TestURLize(t *testing.T) {
+ initCommonTestConfig()
+
+ p := NewPathSpecFromConfig(viper.GetViper())
+
tests := []struct {
input string
expected string
@@ -37,7 +41,7 @@ func TestURLize(t *testing.T) {
}
for _, test := range tests {
- output := URLize(test.input)
+ output := p.URLize(test.input)
if output != test.expected {
t.Errorf("Expected %#v, got %#v\n", test.expected, output)
}
@@ -83,7 +87,8 @@ func doTestAbsURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool,
for _, test := range tests {
viper.Set("BaseURL", test.baseURL)
- output := AbsURL(test.input, addLanguage)
+ p := NewPathSpecFromConfig(viper.GetViper())
+ output := p.AbsURL(test.input, addLanguage)
expected := test.expected
if multilingual && addLanguage {
if !defaultInSubDir && lang == "en" {
@@ -159,8 +164,9 @@ func doTestRelURL(t *testing.T, defaultInSubDir, addLanguage, multilingual bool,
for i, test := range tests {
viper.Set("BaseURL", test.baseURL)
viper.Set("canonifyURLs", test.canonify)
+ p := NewPathSpecFromConfig(viper.GetViper())
- output := RelURL(test.input, addLanguage)
+ output := p.RelURL(test.input, addLanguage)
expected := test.expected
if multilingual && addLanguage {