diff options
Diffstat (limited to 'cache/filecache/filecache_pruner.go')
-rw-r--r-- | cache/filecache/filecache_pruner.go | 117 |
1 files changed, 82 insertions, 35 deletions
diff --git a/cache/filecache/filecache_pruner.go b/cache/filecache/filecache_pruner.go index 322eabf92..c6fd4497e 100644 --- a/cache/filecache/filecache_pruner.go +++ b/cache/filecache/filecache_pruner.go @@ -28,53 +28,100 @@ import ( func (c Caches) Prune() (int, error) { counter := 0 for k, cache := range c { - err := afero.Walk(cache.Fs, "", func(name string, info os.FileInfo, err error) error { - if info == nil { - return nil - } - name = cleanID(name) - - if info.IsDir() { - f, err := cache.Fs.Open(name) - if err != nil { - // This cache dir may not exist. - return nil - } - defer f.Close() - _, err = f.Readdirnames(1) - if err == io.EOF { - // Empty dir. - return cache.Fs.Remove(name) - } + count, err := cache.Prune(false) + + if err != nil { + return counter, errors.Wrapf(err, "failed to prune cache %q", k) + } + + counter += count + + } + + return counter, nil +} + +// Prune removes expired and unused items from this cache. +// If force is set, everything will be removed not considering expiry time. +func (c *Cache) Prune(force bool) (int, error) { + if c.pruneAllRootDir != "" { + return c.pruneRootDir(force) + } + + counter := 0 + + err := afero.Walk(c.Fs, "", func(name string, info os.FileInfo, err error) error { + if info == nil { + return nil + } + + name = cleanID(name) + if info.IsDir() { + f, err := c.Fs.Open(name) + if err != nil { + // This cache dir may not exist. return nil } + defer f.Close() + _, err = f.Readdirnames(1) + if err == io.EOF { + // Empty dir. + return c.Fs.Remove(name) + } + + return nil + } - shouldRemove := cache.isExpired(info.ModTime()) + shouldRemove := force || c.isExpired(info.ModTime()) - if !shouldRemove && len(cache.nlocker.seen) > 0 { - // Remove it if it's not been touched/used in the last build. - _, seen := cache.nlocker.seen[name] - shouldRemove = !seen - } + if !shouldRemove && len(c.nlocker.seen) > 0 { + // Remove it if it's not been touched/used in the last build. + _, seen := c.nlocker.seen[name] + shouldRemove = !seen + } - if shouldRemove { - err := cache.Fs.Remove(name) - if err == nil { - counter++ - } - return err + if shouldRemove { + err := c.Fs.Remove(name) + if err == nil { + counter++ } + return err + } - return nil - }) + return nil + }) - if err != nil { - return counter, errors.Wrapf(err, "failed to prune cache %q", k) + return counter, err +} + +func (c *Cache) pruneRootDir(force bool) (int, error) { + + info, err := c.Fs.Stat(c.pruneAllRootDir) + if err != nil { + if os.IsNotExist(err) { + return 0, nil } + return 0, err + } + if !force && !c.isExpired(info.ModTime()) { + return 0, nil } - return counter, nil + counter := 0 + // Module cache has 0555 directories; make them writable in order to remove content. + afero.Walk(c.Fs, c.pruneAllRootDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return nil + } + if info.IsDir() { + counter++ + c.Fs.Chmod(path, 0777) + } + return nil + }) + return 1, c.Fs.RemoveAll(c.pruneAllRootDir) + } |