hugo

Unnamed repository; edit this file 'description' to name the repository.

git clone git://git.shimmy1996.com/hugo.git
commit 77cbe4d60bfa708cbf695ae5f2524d4f76007e71
parent c507e2717df7dd4b870478033bc5ece0b039a8c4
Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Date:   Fri, 17 Feb 2017 14:22:40 +0100

tplimpl: Refactor imageConfig into a struct

Updates #2701

Diffstat:
Mhugolib/hugo_sites.go | 2--
Mtpl/tplimpl/template_funcs.go | 53++++++++++++++++++-----------------------------------
Mtpl/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
@@ -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
@@ -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
@@ -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) {