mirror of
				https://github.com/gohugoio/hugo.git
				synced 2024-05-11 05:54:58 +00:00 
			
		
		
		
	@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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) },
 | 
			
		||||
 
 | 
			
		||||
@@ -667,14 +667,11 @@ func TestImageConfig(t *testing.T) {
 | 
			
		||||
	f := newTestFuncsterWithViper(v)
 | 
			
		||||
 | 
			
		||||
	for i, this := range []struct {
 | 
			
		||||
		resetCache bool
 | 
			
		||||
		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),
 | 
			
		||||
			expected: image.Config{
 | 
			
		||||
@@ -684,7 +681,6 @@ func TestImageConfig(t *testing.T) {
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			resetCache: true,
 | 
			
		||||
			path:  "a.png",
 | 
			
		||||
			input: blankImage(10, 10),
 | 
			
		||||
			expected: image.Config{
 | 
			
		||||
@@ -694,7 +690,6 @@ func TestImageConfig(t *testing.T) {
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			resetCache: false,
 | 
			
		||||
			path:  "b.png",
 | 
			
		||||
			input: blankImage(20, 15),
 | 
			
		||||
			expected: image.Config{
 | 
			
		||||
@@ -704,7 +699,6 @@ func TestImageConfig(t *testing.T) {
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			resetCache: false,
 | 
			
		||||
			path:  "a.png",
 | 
			
		||||
			input: blankImage(20, 15),
 | 
			
		||||
			expected: image.Config{
 | 
			
		||||
@@ -713,24 +707,10 @@ func TestImageConfig(t *testing.T) {
 | 
			
		||||
				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) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user