forget: Add policy to keep snapshots before a date

This commit is contained in:
Matthew Holt 2018-04-23 14:34:37 -06:00 committed by Alexander Neumann
parent 159badf5ba
commit b52f2aa9a4
4 changed files with 137 additions and 28 deletions

View file

@ -5,6 +5,7 @@ import (
"encoding/json"
"sort"
"strings"
"time"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
@ -33,6 +34,7 @@ type ForgetOptions struct {
Weekly int
Monthly int
Yearly int
NewerThan time.Duration
KeepTags restic.TagLists
Host string
@ -58,6 +60,7 @@ func init() {
f.IntVarP(&forgetOptions.Weekly, "keep-weekly", "w", 0, "keep the last `n` weekly snapshots")
f.IntVarP(&forgetOptions.Monthly, "keep-monthly", "m", 0, "keep the last `n` monthly snapshots")
f.IntVarP(&forgetOptions.Yearly, "keep-yearly", "y", 0, "keep the last `n` yearly snapshots")
f.DurationVar(&forgetOptions.NewerThan, "keep-newer-than", 0, "keep snapshots that were created within this timeframe")
f.Var(&forgetOptions.KeepTags, "keep-tag", "keep snapshots with this `taglist` (can be specified multiple times)")
// Sadly the commonly used shortcut `H` is already used.
@ -163,6 +166,11 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
}
}
var ageCutoff time.Time
if opts.NewerThan > 0 {
ageCutoff = time.Now().Add(-opts.NewerThan)
}
policy := restic.ExpirePolicy{
Last: opts.Last,
Hourly: opts.Hourly,
@ -170,6 +178,7 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
Weekly: opts.Weekly,
Monthly: opts.Monthly,
Yearly: opts.Yearly,
NewerThan: ageCutoff,
Tags: opts.KeepTags,
}

View file

@ -16,6 +16,7 @@ type ExpirePolicy struct {
Weekly int // keep the last n weekly snapshots
Monthly int // keep the last n monthly snapshots
Yearly int // keep the last n yearly snapshots
NewerThan time.Time // keep snapshots newer than this time
Tags []TagList // keep all snapshots that include at least one of the tag lists.
}
@ -39,15 +40,11 @@ func (e ExpirePolicy) String() (s string) {
if e.Yearly > 0 {
keeps = append(keeps, fmt.Sprintf("%d yearly", e.Yearly))
}
s = "keep the last "
for _, k := range keeps {
s += k + ", "
if !e.NewerThan.IsZero() {
keeps = append(keeps, fmt.Sprintf("snapshots newer than %s", e.NewerThan))
}
s = strings.Trim(s, ", ")
s += " snapshots"
return s
return fmt.Sprintf("keep the last %s snapshots", strings.Join(keeps, ", "))
}
// Sum returns the maximum number of snapshots to be kept according to this
@ -133,6 +130,11 @@ func ApplyPolicy(list Snapshots, p ExpirePolicy) (keep, remove Snapshots) {
}
}
// If a timestamp is specified, it's a hard cutoff for older snapshots.
if !p.NewerThan.IsZero() && cur.Time.After(p.NewerThan) {
keepSnap = true
}
// Now update the other buckets and see if they have some counts left.
for i, b := range buckets {
if b.Count > 0 {

View file

@ -171,6 +171,7 @@ var expireTests = []restic.ExpirePolicy{
{Tags: []restic.TagList{{"foo"}}},
{Tags: []restic.TagList{{"foo", "bar"}}},
{Tags: []restic.TagList{{"foo"}, {"bar"}}},
{NewerThan: parseTimeUTC("2016-01-01 01:00:00")},
}
func TestApplyPolicy(t *testing.T) {

View file

@ -0,0 +1,97 @@
[
{
"time": "2016-01-18T12:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-12T21:08:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-12T21:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-09T21:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-08T20:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-07T10:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-06T08:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-05T09:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T16:23:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T12:30:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T12:28:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T12:24:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T12:23:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T11:23:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T10:23:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-03T07:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-01T07:08:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-01T01:03:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-01T01:02:03Z",
"tree": null,
"paths": null
}
]