From 77cbe4d60bfa708cbf695ae5f2524d4f76007e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Fri, 17 Feb 2017 14:22:40 +0100 Subject: [PATCH] tplimpl: Refactor imageConfig into a struct Updates #2701 --- hugolib/hugo_sites.go | 2 -- tpl/tplimpl/template_funcs.go | 53 ++++++++++----------------- tpl/tplimpl/template_funcs_test.go | 58 +++++++++--------------------- 3 files changed, 34 insertions(+), 79 deletions(-) diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index 3cbe4fa90..78ce20b7a 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -190,8 +190,6 @@ func (h *HugoSites) reset() { for i, s := range h.Sites { h.Sites[i] = s.reset() } - - tplimpl.ResetCaches() } func (h *HugoSites) createSitesFromConfig() error { diff --git a/tpl/tplimpl/template_funcs.go b/tpl/tplimpl/template_funcs.go index dae621ac3..20f46a4e2 100644 --- a/tpl/tplimpl/template_funcs.go +++ b/tpl/tplimpl/template_funcs.go @@ -40,6 +40,8 @@ import ( "time" "unicode/utf8" + "github.com/spf13/hugo/hugofs" + "github.com/bep/inflect" "github.com/spf13/afero" "github.com/spf13/cast" @@ -57,6 +59,7 @@ import ( type templateFuncster struct { funcMap template.FuncMap cachedPartials partialCache + image *imageHandler *deps.Deps } @@ -64,6 +67,7 @@ func newTemplateFuncster(deps *deps.Deps) *templateFuncster { return &templateFuncster{ Deps: deps, 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. -// TODO(bep) globals move image config cache to funcster -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 +type imageHandler struct { + imageConfigCache map[string]image.Config sync.RWMutex -} - -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{} + fs *hugofs.Fs } // imageConfig returns the image.Config for the specified path relative to the -// working directory. resetImageConfigCache must be run beforehand. -func (t *templateFuncster) imageConfig(path interface{}) (image.Config, error) { +// working directory. +func (ic *imageHandler) config(path interface{}) (image.Config, error) { filename, err := cast.ToStringE(path) if err != nil { return image.Config{}, err } 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. - defaultImageConfigCache.RLock() - config, ok := defaultImageConfigCache.config[filename] - defaultImageConfigCache.RUnlock() + ic.RLock() + config, ok := ic.imageConfigCache[filename] + ic.RUnlock() if ok { return config, nil } - f, err := t.Fs.WorkingDir.Open(filename) + f, err := ic.fs.WorkingDir.Open(filename) if err != nil { return image.Config{}, err } config, _, err = image.DecodeConfig(f) - defaultImageConfigCache.Lock() - defaultImageConfigCache.config[filename] = config - defaultImageConfigCache.Unlock() + ic.Lock() + ic.imageConfigCache[filename] = config + ic.Unlock() return config, err } @@ -2144,7 +2127,7 @@ func (t *templateFuncster) initFuncMap() { "htmlEscape": htmlEscape, "htmlUnescape": htmlUnescape, "humanize": humanize, - "imageConfig": t.imageConfig, + "imageConfig": t.image.config, "in": in, "index": index, "int": func(v interface{}) (int, error) { return cast.ToIntE(v) }, diff --git a/tpl/tplimpl/template_funcs_test.go b/tpl/tplimpl/template_funcs_test.go index 0fba97bd3..db7533dd3 100644 --- a/tpl/tplimpl/template_funcs_test.go +++ b/tpl/tplimpl/template_funcs_test.go @@ -667,16 +667,13 @@ func TestImageConfig(t *testing.T) { f := newTestFuncsterWithViper(v) for i, this := range []struct { - resetCache bool - path string - input []byte - expected image.Config + path string + input []byte + expected image.Config }{ - // Make sure that the cache is initialized by default. { - resetCache: false, - path: "a.png", - input: blankImage(10, 10), + path: "a.png", + input: blankImage(10, 10), expected: image.Config{ Width: 10, Height: 10, @@ -684,9 +681,8 @@ func TestImageConfig(t *testing.T) { }, }, { - resetCache: true, - path: "a.png", - input: blankImage(10, 10), + path: "a.png", + input: blankImage(10, 10), expected: image.Config{ Width: 10, Height: 10, @@ -694,9 +690,8 @@ func TestImageConfig(t *testing.T) { }, }, { - resetCache: false, - path: "b.png", - input: blankImage(20, 15), + path: "b.png", + input: blankImage(20, 15), expected: image.Config{ Width: 20, Height: 15, @@ -704,33 +699,18 @@ func TestImageConfig(t *testing.T) { }, }, { - resetCache: false, - path: "a.png", - input: blankImage(20, 15), + path: "a.png", + input: blankImage(20, 15), expected: image.Config{ Width: 10, Height: 10, 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) - if this.resetCache { - resetImageConfigCache() - } - - result, err := f.imageConfig(this.path) + result, err := f.image.config(this.path) if err != nil { 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) } - if len(defaultImageConfigCache.config) == 0 { + if len(f.image.imageConfigCache) == 0 { 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") } - 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") } - if _, err := f.imageConfig(""); err == nil { + if _, err := f.image.config(""); err == nil { 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) {