restic/cmd/restic/cmd_cache.go

178 lines
3.7 KiB
Go
Raw Normal View History

2018-05-01 14:22:12 +00:00
package main
import (
"fmt"
2018-10-07 12:37:51 +00:00
"os"
2018-05-01 14:22:12 +00:00
"path/filepath"
"sort"
"strings"
2018-05-01 14:22:12 +00:00
"time"
"github.com/restic/restic/internal/cache"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/fs"
2018-08-19 19:31:53 +00:00
"github.com/restic/restic/internal/ui/table"
2018-05-01 14:22:12 +00:00
"github.com/spf13/cobra"
)
var cmdCache = &cobra.Command{
Use: "cache",
Short: "Operate on local cache directories",
Long: `
The "cache" command allows listing and cleaning local cache directories.
EXIT STATUS
===========
Exit status is 0 if the command was successful, and non-zero if there was any error.
2018-05-01 14:22:12 +00:00
`,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runCache(cacheOptions, globalOptions, args)
},
}
// CacheOptions bundles all options for the snapshots command.
type CacheOptions struct {
Cleanup bool
MaxAge uint
2018-10-07 12:37:51 +00:00
NoSize bool
2018-05-01 14:22:12 +00:00
}
var cacheOptions CacheOptions
func init() {
cmdRoot.AddCommand(cmdCache)
f := cmdCache.Flags()
f.BoolVar(&cacheOptions.Cleanup, "cleanup", false, "remove old cache directories")
f.UintVar(&cacheOptions.MaxAge, "max-age", 30, "max age in `days` for cache directories to be considered old")
2018-10-07 12:37:51 +00:00
f.BoolVar(&cacheOptions.NoSize, "no-size", false, "do not output the size of the cache directories")
2018-05-01 14:22:12 +00:00
}
func runCache(opts CacheOptions, gopts GlobalOptions, args []string) error {
if len(args) > 0 {
return errors.Fatal("the cache command expects no arguments, only options - please see `restic help cache` for usage and flags")
2018-05-01 14:22:12 +00:00
}
if gopts.NoCache {
return errors.Fatal("Refusing to do anything, the cache is disabled")
}
var (
cachedir = gopts.CacheDir
err error
)
if cachedir == "" {
cachedir, err = cache.DefaultDir()
if err != nil {
return err
}
}
if opts.Cleanup || gopts.CleanupCache {
oldDirs, err := cache.OlderThan(cachedir, time.Duration(opts.MaxAge)*24*time.Hour)
if err != nil {
return err
}
if len(oldDirs) == 0 {
Verbosef("no old cache dirs found\n")
return nil
}
Verbosef("remove %d old cache directories\n", len(oldDirs))
for _, item := range oldDirs {
dir := filepath.Join(cachedir, item.Name())
err = fs.RemoveAll(dir)
if err != nil {
Warnf("unable to remove %v: %v\n", dir, err)
}
}
return nil
}
2018-08-19 19:31:53 +00:00
tab := table.New()
type data struct {
ID string
Last string
Old string
2018-10-07 12:37:51 +00:00
Size string
2018-08-19 19:31:53 +00:00
}
tab.AddColumn("Repo ID", "{{ .ID }}")
tab.AddColumn("Last Used", "{{ .Last }}")
tab.AddColumn("Old", "{{ .Old }}")
2018-05-01 14:22:12 +00:00
2018-10-07 12:37:51 +00:00
if !opts.NoSize {
tab.AddColumn("Size", "{{ .Size }}")
}
2018-05-01 14:22:12 +00:00
dirs, err := cache.All(cachedir)
if err != nil {
return err
}
if len(dirs) == 0 {
Printf("no cache dirs found, basedir is %v\n", cachedir)
return nil
}
sort.Slice(dirs, func(i, j int) bool {
return dirs[i].ModTime().Before(dirs[j].ModTime())
})
for _, entry := range dirs {
var old string
if cache.IsOld(entry.ModTime(), time.Duration(opts.MaxAge)*24*time.Hour) {
old = "yes"
}
2018-10-07 12:37:51 +00:00
var size string
if !opts.NoSize {
2018-10-08 13:47:08 +00:00
bytes, err := dirSize(filepath.Join(cachedir, entry.Name()))
2018-10-07 12:37:51 +00:00
if err != nil {
return err
}
size = fmt.Sprintf("%11s", formatBytes(uint64(bytes)))
}
name := entry.Name()
if !strings.HasPrefix(name, "restic-check-cache-") {
name = name[:10]
}
2018-08-19 19:31:53 +00:00
tab.AddRow(data{
name,
2018-05-01 14:22:12 +00:00
fmt.Sprintf("%d days ago", uint(time.Since(entry.ModTime()).Hours()/24)),
old,
2018-10-07 12:37:51 +00:00
size,
2018-05-01 14:22:12 +00:00
})
}
2021-01-30 16:25:10 +00:00
_ = tab.Write(gopts.stdout)
Printf("%d cache dirs in %s\n", len(dirs), cachedir)
2018-05-01 14:22:12 +00:00
return nil
}
2018-10-07 12:37:51 +00:00
func dirSize(path string) (int64, error) {
var size int64
err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if err != nil || info == nil {
return err
}
2018-10-07 12:37:51 +00:00
if !info.IsDir() {
size += info.Size()
}
return nil
2018-10-07 12:37:51 +00:00
})
return size, err
}