cache/filecache: Add a filecache root dir
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 14 Nov 2018 10:53:45 +0000 (11:53 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 14 Nov 2018 22:14:51 +0000 (23:14 +0100)
This is just a safe guard to make sure we don't evict/remove files that do not belong to the cache.

cache/filecache/filecache.go
cache/filecache/filecache_config.go
cache/filecache/filecache_config_test.go
cache/filecache/filecache_test.go
tpl/data/resources_test.go

index da0a90d57dfbab55156da22c3c97f9ac7d640279..a934dd89c35b15a9c0e25722381f88b10461206a 100644 (file)
@@ -31,6 +31,10 @@ import (
        "github.com/spf13/afero"
 )
 
+const (
+       filecacheRootDirname = "filecache"
+)
+
 // Cache caches a set of files in a directory. This is usually a file on
 // disk, but since this is backed by an Afero file system, it can be anything.
 type Cache struct {
@@ -276,11 +280,24 @@ func NewCachesFromPaths(p *paths.Paths) (Caches, error) {
                return nil, err
        }
 
+       genDir := filepath.FromSlash("/_gen")
+
        fs := p.Fs.Source
 
        m := make(Caches)
        for k, v := range dcfg {
-               baseDir := filepath.Join(v.Dir, k)
+               var baseDir string
+               if !strings.Contains(v.Dir, genDir) {
+                       // We do cache eviction (file removes) and since the user can set
+                       // his/hers own cache directory, we really want to make sure
+                       // we do not delete any files that do not belong to this cache.
+                       // We do add the cache name as the root, but this is an extra safe
+                       // guard. We skip the files inside /resources/_gen/ because
+                       // that would be breaking.
+                       baseDir = filepath.Join(v.Dir, filecacheRootDirname, k)
+               } else {
+                       baseDir = filepath.Join(v.Dir, k)
+               }
                if err = fs.MkdirAll(baseDir, 0777); err != nil {
                        return nil, err
                }
index 9913fd7e2327bf2f6e848b042c24645090abedc7..f0dd7295a86e2ceca4862413071a02ef2c2ff764 100644 (file)
@@ -157,6 +157,10 @@ func decodeConfig(p *paths.Paths) (cachesConfig, error) {
                        return c, errors.Errorf("%q must either start with a placeholder (e.g. :cacheDir, :resourceDir) or be absolute", v.Dir)
                }
 
+               if len(v.Dir) < 5 {
+                       return c, errors.Errorf("%q is not a valid cache dir", v.Dir)
+               }
+
                if disabled {
                        v.MaxAge = 0
                }
index 22fb1b56bd5c0b47cacf11396f908f5c30d2198b..abba6c25f51293701618aa0b7c60b3e68c468b65 100644 (file)
@@ -33,6 +33,7 @@ func TestDecodeConfig(t *testing.T) {
        assert := require.New(t)
 
        configStr := `
+resourceDir = "myresources"
 [caches]
 [caches.getJSON]
 maxAge = "10m"
@@ -72,6 +73,7 @@ func TestDecodeConfigIgnoreCache(t *testing.T) {
        assert := require.New(t)
 
        configStr := `
+resourceDir = "myresources"
 ignoreCache = true
 [caches]
 [caches.getJSON]
index b3b8376ed6b2e415b6a106f843589bfee1bc9057..986d41f7b17ce374e046a51afb414f8597e0a4c2 100644 (file)
@@ -41,6 +41,8 @@ func TestFileCache(t *testing.T) {
        for _, cacheDir := range []string{"mycache", ""} {
 
                configStr := `
+workingDir = "/my/work"
+resourceDir = "resources"
 cacheDir = "CACHEDIR"
 [caches]
 [caches.getJSON]
@@ -69,12 +71,20 @@ dir = ":cacheDir/c"
                filename, err := bfs.RealPath("key")
                assert.NoError(err)
                if cacheDir != "" {
-                       assert.Equal(filepath.FromSlash(cacheDir+"/c/getjson/key"), filename)
+                       assert.Equal(filepath.FromSlash(cacheDir+"/c/"+filecacheRootDirname+"/getjson/key"), filename)
                } else {
                        // Temp dir.
-                       assert.Regexp(regexp.MustCompile("hugo_cache.*key"), filename)
+                       assert.Regexp(regexp.MustCompile(".*hugo_cache.*"+filecacheRootDirname+".*key"), filename)
                }
 
+               c = caches.Get("images")
+               assert.NotNil(c)
+               assert.Equal(time.Duration(-1), c.maxAge)
+               bfs, ok = c.Fs.(*afero.BasePathFs)
+               assert.True(ok)
+               filename, _ = bfs.RealPath("key")
+               assert.Equal(filepath.FromSlash("/my/work/resources/_gen/images/key"), filename)
+
                rf := func(s string) func() (io.ReadCloser, error) {
                        return func() (io.ReadCloser, error) {
                                return struct {
@@ -149,6 +159,7 @@ func TestFileCacheConcurrent(t *testing.T) {
        assert := require.New(t)
 
        configStr := `
+resourceDir = "myresources"
 [caches]
 [caches.getjson]
 maxAge = "1s"
index 54eb123ee7571db5845626ee1433d273c1cb7404..b143bb1a3d1eca903920a52403fd9769a714bab0 100644 (file)
@@ -180,6 +180,7 @@ func TestScpGetRemoteParallel(t *testing.T) {
 }
 
 func newDeps(cfg config.Provider) *deps.Deps {
+       cfg.Set("resourceDir", "resources")
        l := langs.NewLanguage("en", cfg)
        l.Set("i18nDir", "i18n")
        cs, err := helpers.NewContentSpec(l)