tplimpl: Refactor imageConfig into a struct
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 17 Feb 2017 13:22:40 +0000 (14:22 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 17 Feb 2017 16:15:26 +0000 (17:15 +0100)
Updates #2701

hugolib/hugo_sites.go
tpl/tplimpl/template_funcs.go
tpl/tplimpl/template_funcs_test.go

index 3cbe4fa90e72efbbf708c0d7013ae35742057ddf..78ce20b7a38e0fbb76283a3c0b39acbd29b8e6d5 100644 (file)
@@ -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 {
index dae621ac36329104d308b1b187da1bc675183670..20f46a4e2a9028e7b0ecf8f77efe4871a238f9a8 100644 (file)
@@ -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) },
index 0fba97bd32d9ecd9af253b23932a4417c21abf4b..db7533dd35f3632b276f00d80b0adca84cea01d2 100644 (file)
@@ -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) {