mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
c507e2717d
commit
77cbe4d60b
3 changed files with 34 additions and 79 deletions
|
@ -190,8 +190,6 @@ func (h *HugoSites) reset() {
|
||||||
for i, s := range h.Sites {
|
for i, s := range h.Sites {
|
||||||
h.Sites[i] = s.reset()
|
h.Sites[i] = s.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
tplimpl.ResetCaches()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HugoSites) createSitesFromConfig() error {
|
func (h *HugoSites) createSitesFromConfig() error {
|
||||||
|
|
|
@ -40,6 +40,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/spf13/hugo/hugofs"
|
||||||
|
|
||||||
"github.com/bep/inflect"
|
"github.com/bep/inflect"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
|
@ -57,6 +59,7 @@ import (
|
||||||
type templateFuncster struct {
|
type templateFuncster struct {
|
||||||
funcMap template.FuncMap
|
funcMap template.FuncMap
|
||||||
cachedPartials partialCache
|
cachedPartials partialCache
|
||||||
|
image *imageHandler
|
||||||
*deps.Deps
|
*deps.Deps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +67,7 @@ func newTemplateFuncster(deps *deps.Deps) *templateFuncster {
|
||||||
return &templateFuncster{
|
return &templateFuncster{
|
||||||
Deps: deps,
|
Deps: deps,
|
||||||
cachedPartials: partialCache{p: make(map[string]template.HTML)},
|
cachedPartials: partialCache{p: make(map[string]template.HTML)},
|
||||||
|
image: &imageHandler{fs: deps.Fs, imageConfigCache: map[string]image.Config{}},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,64 +399,43 @@ func intersect(l1, l2 interface{}) (interface{}, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetCaches resets all caches that might be used during build.
|
type imageHandler struct {
|
||||||
// TODO(bep) globals move image config cache to funcster
|
imageConfigCache map[string]image.Config
|
||||||
func ResetCaches() {
|
|
||||||
resetImageConfigCache()
|
|
||||||
}
|
|
||||||
|
|
||||||
// imageConfigCache is a lockable cache for image.Config objects. It must be
|
|
||||||
// locked before reading or writing to config.
|
|
||||||
type imageConfigCache struct {
|
|
||||||
config map[string]image.Config
|
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
fs *hugofs.Fs
|
||||||
|
|
||||||
var defaultImageConfigCache = imageConfigCache{
|
|
||||||
config: map[string]image.Config{},
|
|
||||||
}
|
|
||||||
|
|
||||||
// resetImageConfigCache initializes and resets the imageConfig cache for the
|
|
||||||
// imageConfig template function. This should be run once before every batch of
|
|
||||||
// template renderers so the cache is cleared for new data.
|
|
||||||
func resetImageConfigCache() {
|
|
||||||
defaultImageConfigCache.Lock()
|
|
||||||
defer defaultImageConfigCache.Unlock()
|
|
||||||
|
|
||||||
defaultImageConfigCache.config = map[string]image.Config{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// imageConfig returns the image.Config for the specified path relative to the
|
// imageConfig returns the image.Config for the specified path relative to the
|
||||||
// working directory. resetImageConfigCache must be run beforehand.
|
// working directory.
|
||||||
func (t *templateFuncster) imageConfig(path interface{}) (image.Config, error) {
|
func (ic *imageHandler) config(path interface{}) (image.Config, error) {
|
||||||
filename, err := cast.ToStringE(path)
|
filename, err := cast.ToStringE(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return image.Config{}, err
|
return image.Config{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if filename == "" {
|
if filename == "" {
|
||||||
return image.Config{}, errors.New("imageConfig needs a filename")
|
return image.Config{}, errors.New("config needs a filename")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cache for image config.
|
// Check cache for image config.
|
||||||
defaultImageConfigCache.RLock()
|
ic.RLock()
|
||||||
config, ok := defaultImageConfigCache.config[filename]
|
config, ok := ic.imageConfigCache[filename]
|
||||||
defaultImageConfigCache.RUnlock()
|
ic.RUnlock()
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := t.Fs.WorkingDir.Open(filename)
|
f, err := ic.fs.WorkingDir.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return image.Config{}, err
|
return image.Config{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config, _, err = image.DecodeConfig(f)
|
config, _, err = image.DecodeConfig(f)
|
||||||
|
|
||||||
defaultImageConfigCache.Lock()
|
ic.Lock()
|
||||||
defaultImageConfigCache.config[filename] = config
|
ic.imageConfigCache[filename] = config
|
||||||
defaultImageConfigCache.Unlock()
|
ic.Unlock()
|
||||||
|
|
||||||
return config, err
|
return config, err
|
||||||
}
|
}
|
||||||
|
@ -2144,7 +2127,7 @@ func (t *templateFuncster) initFuncMap() {
|
||||||
"htmlEscape": htmlEscape,
|
"htmlEscape": htmlEscape,
|
||||||
"htmlUnescape": htmlUnescape,
|
"htmlUnescape": htmlUnescape,
|
||||||
"humanize": humanize,
|
"humanize": humanize,
|
||||||
"imageConfig": t.imageConfig,
|
"imageConfig": t.image.config,
|
||||||
"in": in,
|
"in": in,
|
||||||
"index": index,
|
"index": index,
|
||||||
"int": func(v interface{}) (int, error) { return cast.ToIntE(v) },
|
"int": func(v interface{}) (int, error) { return cast.ToIntE(v) },
|
||||||
|
|
|
@ -667,16 +667,13 @@ func TestImageConfig(t *testing.T) {
|
||||||
f := newTestFuncsterWithViper(v)
|
f := newTestFuncsterWithViper(v)
|
||||||
|
|
||||||
for i, this := range []struct {
|
for i, this := range []struct {
|
||||||
resetCache bool
|
path string
|
||||||
path string
|
input []byte
|
||||||
input []byte
|
expected image.Config
|
||||||
expected image.Config
|
|
||||||
}{
|
}{
|
||||||
// Make sure that the cache is initialized by default.
|
|
||||||
{
|
{
|
||||||
resetCache: false,
|
path: "a.png",
|
||||||
path: "a.png",
|
input: blankImage(10, 10),
|
||||||
input: blankImage(10, 10),
|
|
||||||
expected: image.Config{
|
expected: image.Config{
|
||||||
Width: 10,
|
Width: 10,
|
||||||
Height: 10,
|
Height: 10,
|
||||||
|
@ -684,9 +681,8 @@ func TestImageConfig(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resetCache: true,
|
path: "a.png",
|
||||||
path: "a.png",
|
input: blankImage(10, 10),
|
||||||
input: blankImage(10, 10),
|
|
||||||
expected: image.Config{
|
expected: image.Config{
|
||||||
Width: 10,
|
Width: 10,
|
||||||
Height: 10,
|
Height: 10,
|
||||||
|
@ -694,9 +690,8 @@ func TestImageConfig(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resetCache: false,
|
path: "b.png",
|
||||||
path: "b.png",
|
input: blankImage(20, 15),
|
||||||
input: blankImage(20, 15),
|
|
||||||
expected: image.Config{
|
expected: image.Config{
|
||||||
Width: 20,
|
Width: 20,
|
||||||
Height: 15,
|
Height: 15,
|
||||||
|
@ -704,33 +699,18 @@ func TestImageConfig(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resetCache: false,
|
path: "a.png",
|
||||||
path: "a.png",
|
input: blankImage(20, 15),
|
||||||
input: blankImage(20, 15),
|
|
||||||
expected: image.Config{
|
expected: image.Config{
|
||||||
Width: 10,
|
Width: 10,
|
||||||
Height: 10,
|
Height: 10,
|
||||||
ColorModel: color.NRGBAModel,
|
ColorModel: color.NRGBAModel,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
resetCache: true,
|
|
||||||
path: "a.png",
|
|
||||||
input: blankImage(20, 15),
|
|
||||||
expected: image.Config{
|
|
||||||
Width: 20,
|
|
||||||
Height: 15,
|
|
||||||
ColorModel: color.NRGBAModel,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} {
|
} {
|
||||||
afero.WriteFile(f.Fs.Source, filepath.Join(workingDir, this.path), this.input, 0755)
|
afero.WriteFile(f.Fs.Source, filepath.Join(workingDir, this.path), this.input, 0755)
|
||||||
|
|
||||||
if this.resetCache {
|
result, err := f.image.config(this.path)
|
||||||
resetImageConfigCache()
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := f.imageConfig(this.path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("imageConfig returned error: %s", err)
|
t.Errorf("imageConfig returned error: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -739,29 +719,23 @@ func TestImageConfig(t *testing.T) {
|
||||||
t.Errorf("[%d] imageConfig: expected '%v', got '%v'", i, this.expected, result)
|
t.Errorf("[%d] imageConfig: expected '%v', got '%v'", i, this.expected, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(defaultImageConfigCache.config) == 0 {
|
if len(f.image.imageConfigCache) == 0 {
|
||||||
t.Error("defaultImageConfigCache should have at least 1 item")
|
t.Error("defaultImageConfigCache should have at least 1 item")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := f.imageConfig(t); err == nil {
|
if _, err := f.image.config(t); err == nil {
|
||||||
t.Error("Expected error from imageConfig when passed invalid path")
|
t.Error("Expected error from imageConfig when passed invalid path")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := f.imageConfig("non-existent.png"); err == nil {
|
if _, err := f.image.config("non-existent.png"); err == nil {
|
||||||
t.Error("Expected error from imageConfig when passed non-existent file")
|
t.Error("Expected error from imageConfig when passed non-existent file")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := f.imageConfig(""); err == nil {
|
if _, err := f.image.config(""); err == nil {
|
||||||
t.Error("Expected error from imageConfig when passed empty path")
|
t.Error("Expected error from imageConfig when passed empty path")
|
||||||
}
|
}
|
||||||
|
|
||||||
// test cache clearing
|
|
||||||
ResetCaches()
|
|
||||||
|
|
||||||
if len(defaultImageConfigCache.config) != 0 {
|
|
||||||
t.Error("ResetCaches should have cleared defaultImageConfigCache")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIn(t *testing.T) {
|
func TestIn(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue