Add 'forget' command

This commit is contained in:
Alexander Neumann 2016-08-20 17:43:25 +02:00
parent cbd457e557
commit bf47dba1c4

View file

@ -0,0 +1,153 @@
package main
import (
"fmt"
"io"
"path"
"restic"
"restic/backend"
)
// CmdForget implements the 'forget' command.
type CmdForget struct {
Last int `short:"l" long:"keep-last" description:"keep the last n snapshots"`
Hourly int `short:"H" long:"keep-hourly" description:"keep the last n hourly snapshots"`
Daily int `short:"d" long:"keep-daily" description:"keep the last n daily snapshots"`
Weekly int `short:"w" long:"keep-weekly" description:"keep the last n weekly snapshots"`
Monthly int `short:"m" long:"keep-monthly" description:"keep the last n monthly snapshots"`
Yearly int `short:"y" long:"keep-yearly" description:"keep the last n yearly snapshots"`
DryRun bool `short:"n" long:"dry-run" description:"do not delete anything, just print what would be done"`
global *GlobalOptions
}
func init() {
_, err := parser.AddCommand("forget",
"removes snapshots from a repository",
"The forget command removes snapshots according to a policy.",
&CmdForget{global: &globalOpts})
if err != nil {
panic(err)
}
}
// Usage returns usage information for 'forget'.
func (cmd CmdForget) Usage() string {
return "[snapshot ID] ..."
}
func printSnapshots(w io.Writer, snapshots restic.Snapshots) {
tab := NewTable()
tab.Header = fmt.Sprintf("%-8s %-19s %-10s %s", "ID", "Date", "Host", "Directory")
tab.RowFormat = "%-8s %-19s %-10s %s"
for _, sn := range snapshots {
if len(sn.Paths) == 0 {
continue
}
id := sn.ID()
tab.Rows = append(tab.Rows, []interface{}{id.Str(), sn.Time.Format(TimeFormat), sn.Hostname, sn.Paths[0]})
if len(sn.Paths) > 1 {
for _, path := range sn.Paths[1:] {
tab.Rows = append(tab.Rows, []interface{}{"", "", "", path})
}
}
}
tab.Write(w)
}
// Execute runs the 'forget' command.
func (cmd CmdForget) Execute(args []string) error {
repo, err := cmd.global.OpenRepository()
if err != nil {
return err
}
lock, err := lockRepoExclusive(repo)
defer unlockRepo(lock)
if err != nil {
return err
}
err = repo.LoadIndex()
if err != nil {
return err
}
// first, process all snapshot IDs given as arguments
for _, s := range args {
id, err := restic.FindSnapshot(repo, s)
if err != nil {
return err
}
if !cmd.DryRun {
err = repo.Backend().Remove(backend.Snapshot, id.String())
if err != nil {
return err
}
cmd.global.Verbosef("removed snapshot %v\n", id.Str())
} else {
cmd.global.Verbosef("would removed snapshot %v\n", id.Str())
}
}
// then, load all remaining snapshots
snapshots, err := restic.LoadAllSnapshots(repo)
if err != nil {
return err
}
// group by hostname and dirs
type key struct {
Hostname string
Dirs string
}
snapshotGroups := make(map[key]restic.Snapshots)
for _, sn := range snapshots {
k := key{Hostname: sn.Hostname, Dirs: path.Join(sn.Paths...)}
list := snapshotGroups[k]
list = append(list, sn)
snapshotGroups[k] = list
}
policy := restic.ExpirePolicy{
Last: cmd.Last,
Hourly: cmd.Hourly,
Daily: cmd.Daily,
Weekly: cmd.Weekly,
Monthly: cmd.Monthly,
Yearly: cmd.Yearly,
}
for key, snapshotGroup := range snapshotGroups {
cmd.global.Printf("snapshots for host %v, directories %v:\n\n", key.Hostname, key.Dirs)
keep, remove := restic.ApplyPolicy(snapshotGroup, policy)
cmd.global.Printf("keep %d snapshots:\n", len(keep))
printSnapshots(cmd.global.stdout, keep)
cmd.global.Printf("\n")
cmd.global.Printf("remove %d snapshots:\n", len(remove))
printSnapshots(cmd.global.stdout, remove)
cmd.global.Printf("\n")
if !cmd.DryRun {
for _, sn := range remove {
err = repo.Backend().Remove(backend.Snapshot, sn.ID().String())
if err != nil {
return err
}
}
}
}
return nil
}