From 12246969db0d7f60778c2d0dede869c479a35237 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 19 Aug 2018 15:29:05 +0200 Subject: [PATCH 1/5] ui/table: Add small package for writing tables --- internal/ui/table/table.go | 206 ++++++++++++++++++++++++++++++++ internal/ui/table/table_test.go | 162 +++++++++++++++++++++++++ 2 files changed, 368 insertions(+) create mode 100644 internal/ui/table/table.go create mode 100644 internal/ui/table/table_test.go diff --git a/internal/ui/table/table.go b/internal/ui/table/table.go new file mode 100644 index 000000000..8939f2ac9 --- /dev/null +++ b/internal/ui/table/table.go @@ -0,0 +1,206 @@ +package table + +import ( + "bytes" + "io" + "strings" + + "text/template" +) + +// Table contains data for a table to be printed. +type Table struct { + columns []string + templates []*template.Template + data []interface{} + footer []string + + CellSeparator string + PrintHeader func(io.Writer, string) error + PrintSeparator func(io.Writer, string) error + PrintData func(io.Writer, int, string) error + PrintFooter func(io.Writer, string) error +} + +var funcmap = template.FuncMap{ + "join": strings.Join, +} + +// New initializes a new Table +func New() *Table { + p := func(w io.Writer, s string) error { + _, err := w.Write(append([]byte(s), '\n')) + return err + } + return &Table{ + CellSeparator: " ", + PrintHeader: p, + PrintSeparator: p, + PrintData: func(w io.Writer, _ int, s string) error { + return p(w, s) + }, + PrintFooter: p, + } +} + +// AddColumn adds a new header field with the header and format, which is +// expected to be template string compatible with text/template. When compiling +// the format fails, AddColumn panics. +func (t *Table) AddColumn(header, format string) { + t.columns = append(t.columns, header) + tmpl, err := template.New("template for " + header).Funcs(funcmap).Parse(format) + if err != nil { + panic(err) + } + + t.templates = append(t.templates, tmpl) +} + +// AddRow adds a new row to the table, which is filled with data. +func (t *Table) AddRow(data interface{}) { + t.data = append(t.data, data) +} + +// AddFooter prints line after the table +func (t *Table) AddFooter(line string) { + t.footer = append(t.footer, line) +} + +func printLine(w io.Writer, print func(io.Writer, string) error, sep string, data []string, widths []int) error { + var fields [][]string + + maxLines := 1 + for _, d := range data { + lines := strings.Split(d, "\n") + if len(lines) > maxLines { + maxLines = len(lines) + } + fields = append(fields, lines) + } + + for i := 0; i < maxLines; i++ { + var s string + + for fieldNum, lines := range fields { + var v string + + if i < len(lines) { + v += lines[i] + } + + // apply padding + pad := widths[fieldNum] - len(v) + if pad > 0 { + v += strings.Repeat(" ", pad) + } + + if fieldNum > 0 { + v = sep + v + } + + s += v + } + + err := print(w, strings.TrimRight(s, " ")) + if err != nil { + return err + } + } + + return nil +} + +// Write prints the table to w. +func (t *Table) Write(w io.Writer) error { + columns := len(t.templates) + if columns == 0 { + return nil + } + + // collect all data fields from all columns + lines := make([][]string, 0, len(t.data)) + buf := bytes.NewBuffer(nil) + + for _, data := range t.data { + row := make([]string, 0, len(t.templates)) + for _, tmpl := range t.templates { + err := tmpl.Execute(buf, data) + if err != nil { + return err + } + + row = append(row, string(buf.Bytes())) + buf.Reset() + } + lines = append(lines, row) + } + + // find max width for each cell + columnWidths := make([]int, columns) + for i, desc := range t.columns { + for _, line := range strings.Split(desc, "\n") { + if columnWidths[i] < len(line) { + columnWidths[i] = len(desc) + } + } + } + for _, line := range lines { + for i, content := range line { + for _, l := range strings.Split(content, "\n") { + if columnWidths[i] < len(l) { + columnWidths[i] = len(l) + } + } + } + } + + // calculate the total width of the table + totalWidth := 0 + for _, width := range columnWidths { + totalWidth += width + } + totalWidth += (columns - 1) * len(t.CellSeparator) + + // write header + if len(t.columns) > 0 { + err := printLine(w, t.PrintHeader, t.CellSeparator, t.columns, columnWidths) + if err != nil { + return err + } + + // draw separation line + err = t.PrintSeparator(w, strings.Repeat("-", totalWidth)) + if err != nil { + return err + } + } + + // write all the lines + for i, line := range lines { + print := func(w io.Writer, s string) error { + return t.PrintData(w, i, s) + } + err := printLine(w, print, t.CellSeparator, line, columnWidths) + if err != nil { + return err + } + } + + // draw separation line + err := t.PrintSeparator(w, strings.Repeat("-", totalWidth)) + if err != nil { + return err + } + + if len(t.footer) > 0 { + // write the footer + for _, line := range t.footer { + err := t.PrintFooter(w, line) + if err != nil { + return err + } + } + } + + return nil +} diff --git a/internal/ui/table/table_test.go b/internal/ui/table/table_test.go new file mode 100644 index 000000000..47b180a91 --- /dev/null +++ b/internal/ui/table/table_test.go @@ -0,0 +1,162 @@ +package table + +import ( + "bytes" + "strings" + "testing" +) + +func TestTable(t *testing.T) { + var tests = []struct { + create func(t testing.TB) *Table + output string + }{ + { + func(t testing.TB) *Table { + return New() + }, + "", + }, + { + func(t testing.TB) *Table { + table := New() + table.AddColumn("first column", "data: {{.First}}") + table.AddRow(struct{ First string }{"first data field"}) + return table + }, + ` +first column +---------------------- +data: first data field +---------------------- +`, + }, + { + func(t testing.TB) *Table { + table := New() + table.AddColumn(" first column ", "data: {{.First}}") + table.AddRow(struct{ First string }{"d"}) + return table + }, + ` + first column +---------------- +data: d +---------------- +`, + }, + { + func(t testing.TB) *Table { + table := New() + table.AddColumn("first column", "data: {{.First}}") + table.AddRow(struct{ First string }{"first data field"}) + table.AddRow(struct{ First string }{"second data field"}) + table.AddFooter("footer1") + table.AddFooter("footer2") + return table + }, + ` +first column +----------------------- +data: first data field +data: second data field +----------------------- +footer1 +footer2 +`, + }, + { + func(t testing.TB) *Table { + table := New() + table.AddColumn(" first name", `{{printf "%12s" .FirstName}}`) + table.AddColumn("last name", "{{.LastName}}") + table.AddRow(struct{ FirstName, LastName string }{"firstname", "lastname"}) + table.AddRow(struct{ FirstName, LastName string }{"John", "Doe"}) + table.AddRow(struct{ FirstName, LastName string }{"Johann", "van den Berjen"}) + return table + }, + ` + first name last name +---------------------------- + firstname lastname + John Doe + Johann van den Berjen +---------------------------- +`, + }, + { + func(t testing.TB) *Table { + table := New() + table.AddColumn("host name", `{{.Host}}`) + table.AddColumn("time", `{{.Time}}`) + table.AddColumn("zz", "xxx") + table.AddColumn("tags", `{{join .Tags ","}}`) + table.AddColumn("dirs", `{{join .Dirs ","}}`) + + type data struct { + Host string + Time string + Tags, Dirs []string + } + table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"work"}, []string{"/home/user/work"}}) + table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"other"}, []string{"/home/user/other"}}) + table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"other"}, []string{"/home/user/other"}}) + return table + }, + ` +host name time zz tags dirs +------------------------------------------------------------ +foo 2018-08-19 22:22:22 xxx work /home/user/work +foo 2018-08-19 22:22:22 xxx other /home/user/other +foo 2018-08-19 22:22:22 xxx other /home/user/other +------------------------------------------------------------ +`, + }, + { + func(t testing.TB) *Table { + table := New() + table.AddColumn("host name", `{{.Host}}`) + table.AddColumn("time", `{{.Time}}`) + table.AddColumn("zz", "xxx") + table.AddColumn("tags", `{{join .Tags "\n"}}`) + table.AddColumn("dirs", `{{join .Dirs "\n"}}`) + + type data struct { + Host string + Time string + Tags, Dirs []string + } + table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"work", "go"}, []string{"/home/user/work", "/home/user/go"}}) + table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"other"}, []string{"/home/user/other"}}) + table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"other", "bar"}, []string{"/home/user/other"}}) + return table + }, + ` +host name time zz tags dirs +------------------------------------------------------------ +foo 2018-08-19 22:22:22 xxx work /home/user/work + go /home/user/go +foo 2018-08-19 22:22:22 xxx other /home/user/other +foo 2018-08-19 22:22:22 xxx other /home/user/other + bar +------------------------------------------------------------ +`, + }, + } + + for _, test := range tests { + t.Run("", func(t *testing.T) { + table := test.create(t) + buf := bytes.NewBuffer(nil) + err := table.Write(buf) + if err != nil { + t.Fatal(err) + } + + want := strings.TrimLeft(test.output, "\n") + if string(buf.Bytes()) != want { + t.Errorf("wrong output\n---- want ---\n%s\n---- got ---\n%s\n-------\n", want, buf.Bytes()) + } + }) + } +} From 9fd3796d93b6e5a05ed76bb3ac303dc892afb19e Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Wed, 4 Jul 2018 23:05:38 +0200 Subject: [PATCH 2/5] forget: Display reasons why snapshots are kept This change displays the reasons for keeping a snapshot in the table, unless `--compact` is specified. --- cmd/restic/cmd_forget.go | 6 +- cmd/restic/cmd_snapshots.go | 121 +- internal/restic/snapshot_policy.go | 67 +- internal/restic/snapshot_policy_test.go | 79 +- .../restic/testdata/policy_keep_snapshots_0 | 2363 +++++++++++---- .../restic/testdata/policy_keep_snapshots_1 | 236 +- .../restic/testdata/policy_keep_snapshots_10 | 239 +- .../restic/testdata/policy_keep_snapshots_11 | 52 +- .../restic/testdata/policy_keep_snapshots_12 | 98 +- .../restic/testdata/policy_keep_snapshots_13 | 103 +- .../restic/testdata/policy_keep_snapshots_14 | 144 +- .../restic/testdata/policy_keep_snapshots_15 | 172 +- .../restic/testdata/policy_keep_snapshots_16 | 77 +- .../restic/testdata/policy_keep_snapshots_17 | 258 +- .../restic/testdata/policy_keep_snapshots_18 | 569 +++- .../restic/testdata/policy_keep_snapshots_19 | 149 +- .../restic/testdata/policy_keep_snapshots_2 | 351 ++- .../restic/testdata/policy_keep_snapshots_20 | 603 ++-- .../restic/testdata/policy_keep_snapshots_21 | 29 +- .../restic/testdata/policy_keep_snapshots_22 | 29 +- .../restic/testdata/policy_keep_snapshots_23 | 71 +- .../restic/testdata/policy_keep_snapshots_24 | 407 ++- .../restic/testdata/policy_keep_snapshots_25 | 407 ++- .../restic/testdata/policy_keep_snapshots_26 | 1376 ++++++--- .../restic/testdata/policy_keep_snapshots_3 | 2475 ++++++++++++---- .../restic/testdata/policy_keep_snapshots_4 | 2569 +++++++++++++---- .../restic/testdata/policy_keep_snapshots_5 | 466 ++- .../restic/testdata/policy_keep_snapshots_6 | 75 +- .../restic/testdata/policy_keep_snapshots_7 | 236 +- .../restic/testdata/policy_keep_snapshots_8 | 696 ++++- .../restic/testdata/policy_keep_snapshots_9 | 152 +- 31 files changed, 11213 insertions(+), 3462 deletions(-) diff --git a/cmd/restic/cmd_forget.go b/cmd/restic/cmd_forget.go index 4afef1380..423a1e5e9 100644 --- a/cmd/restic/cmd_forget.go +++ b/cmd/restic/cmd_forget.go @@ -206,17 +206,17 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error { } Verbosef(":\n\n") - keep, remove := restic.ApplyPolicy(snapshotGroup, policy) + keep, remove, reasons := restic.ApplyPolicy(snapshotGroup, policy) if len(keep) != 0 && !gopts.Quiet { Printf("keep %d snapshots:\n", len(keep)) - PrintSnapshots(globalOptions.stdout, keep, opts.Compact) + PrintSnapshots(globalOptions.stdout, keep, reasons, opts.Compact) Printf("\n") } if len(remove) != 0 && !gopts.Quiet { Printf("remove %d snapshots:\n", len(remove)) - PrintSnapshots(globalOptions.stdout, remove, opts.Compact) + PrintSnapshots(globalOptions.stdout, remove, nil, opts.Compact) Printf("\n") } diff --git a/cmd/restic/cmd_snapshots.go b/cmd/restic/cmd_snapshots.go index 5dfb45e97..e456514c3 100644 --- a/cmd/restic/cmd_snapshots.go +++ b/cmd/restic/cmd_snapshots.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/restic/restic/internal/restic" + "github.com/restic/restic/internal/ui/table" "github.com/spf13/cobra" ) @@ -81,7 +82,7 @@ func runSnapshots(opts SnapshotOptions, gopts GlobalOptions, args []string) erro } return nil } - PrintSnapshots(gopts.stdout, list, opts.Compact) + PrintSnapshots(gopts.stdout, list, nil, opts.Compact) return nil } @@ -123,7 +124,16 @@ func FilterLastSnapshots(list restic.Snapshots) restic.Snapshots { } // PrintSnapshots prints a text table of the snapshots in list to stdout. -func PrintSnapshots(stdout io.Writer, list restic.Snapshots, compact bool) { +func PrintSnapshots(stdout io.Writer, list restic.Snapshots, reasons []restic.KeepReason, compact bool) { + // keep the reasons a snasphot is being kept in a map, so that it doesn't + // get lost when the list of snapshots is sorted + keepReasons := make(map[restic.ID]restic.KeepReason, len(reasons)) + if len(reasons) > 0 { + for i, sn := range list { + id := sn.ID() + keepReasons[*id] = reasons[i] + } + } // always sort the snapshots so that the newer ones are listed last sort.SliceStable(list, func(i, j int) bool { @@ -143,71 +153,72 @@ func PrintSnapshots(stdout io.Writer, list restic.Snapshots, compact bool) { } } - tab := NewTable() - if !compact { - tab.Header = fmt.Sprintf("%-8s %-19s %-*s %-*s %-3s %s", "ID", "Date", -maxHost, "Host", -maxTag, "Tags", "", "Directory") - tab.RowFormat = fmt.Sprintf("%%-8s %%-19s %%%ds %%%ds %%-3s %%s", -maxHost, -maxTag) + tab := table.New() + + if compact { + tab.AddColumn("ID", "{{ .ID }}") + tab.AddColumn("Time", "{{ .Timestamp }}") + tab.AddColumn("Host", "{{ .Hostname }}") + tab.AddColumn("Tags ", `{{ join .Tags "\n" }}`) } else { - tab.Header = fmt.Sprintf("%-8s %-19s %-*s %-*s", "ID", "Date", -maxHost, "Host", -maxTag, "Tags") - tab.RowFormat = fmt.Sprintf("%%-8s %%-19s %%%ds %%s", -maxHost) + tab.AddColumn("ID", "{{ .ID }}") + tab.AddColumn("Time", "{{ .Timestamp }}") + tab.AddColumn("Host ", "{{ .Hostname }}") + tab.AddColumn("Tags ", `{{ join .Tags "," }}`) + if len(reasons) > 0 { + tab.AddColumn("Reasons", `{{ join .Reasons "\n" }}`) + } + tab.AddColumn("Paths", `{{ join .Paths "\n" }}`) } + type snapshot struct { + ID string + Timestamp string + Hostname string + Tags []string + Reasons []string + Paths []string + } + + var multiline bool for _, sn := range list { - if len(sn.Paths) == 0 { - continue + data := snapshot{ + ID: sn.ID().Str(), + Timestamp: sn.Time.Format(TimeFormat), + Hostname: sn.Hostname, + Tags: sn.Tags, + Paths: sn.Paths, } - firstTag := "" - if len(sn.Tags) > 0 { - firstTag = sn.Tags[0] + if len(reasons) > 0 { + id := sn.ID() + data.Reasons = keepReasons[*id].Matches } - rows := len(sn.Paths) - if rows < len(sn.Tags) { - rows = len(sn.Tags) + if len(sn.Paths) > 1 { + multiline = true } - treeElement := " " - if rows != 1 { - treeElement = "┌──" - } - - if !compact { - tab.Rows = append(tab.Rows, []interface{}{sn.ID().Str(), sn.Time.Format(TimeFormat), sn.Hostname, firstTag, treeElement, sn.Paths[0]}) - } else { - allTags := "" - for _, tag := range sn.Tags { - allTags += tag + " " - } - tab.Rows = append(tab.Rows, []interface{}{sn.ID().Str(), sn.Time.Format(TimeFormat), sn.Hostname, allTags}) - continue - } - - if len(sn.Tags) > rows { - rows = len(sn.Tags) - } - - for i := 1; i < rows; i++ { - path := "" - if len(sn.Paths) > i { - path = sn.Paths[i] - } - - tag := "" - if len(sn.Tags) > i { - tag = sn.Tags[i] - } - - treeElement := "│" - if i == (rows - 1) { - treeElement = "└──" - } - - tab.Rows = append(tab.Rows, []interface{}{"", "", "", tag, treeElement, path}) - } + tab.AddRow(data) } - tab.Footer = fmt.Sprintf("%d snapshots", len(list)) + tab.AddFooter(fmt.Sprintf("%d snapshots", len(list))) + + if multiline { + // print an additional blank line between snapshots + + var last int + tab.PrintData = func(w io.Writer, idx int, s string) error { + var err error + if idx == last { + _, err = fmt.Fprintf(w, "%s\n", s) + } else { + _, err = fmt.Fprintf(w, "\n%s\n", s) + } + last = idx + return err + } + } tab.Write(stdout) } diff --git a/internal/restic/snapshot_policy.go b/internal/restic/snapshot_policy.go index df142c0fb..7fc5e384e 100644 --- a/internal/restic/snapshot_policy.go +++ b/internal/restic/snapshot_policy.go @@ -6,6 +6,8 @@ import ( "sort" "strings" "time" + + "github.com/restic/restic/internal/debug" ) // ExpirePolicy configures which snapshots should be automatically removed. @@ -125,41 +127,70 @@ func findLatestTimestamp(list Snapshots) time.Time { return latest } +// KeepReason specifies why a particular snapshot was kept, and the counters at +// that point in the policy evaluation. +type KeepReason struct { + Snapshot *Snapshot `json:"snapshot"` + + // description text which criteria match, e.g. "daily", "monthly" + Matches []string `json:"matches"` + + // the counters after evaluating the current snapshot + Counters struct { + Last int `json:"last,omitempty"` + Hourly int `json:"hourly,omitempty"` + Daily int `json:"daily,omitempty"` + Weekly int `json:"weekly,omitempty"` + Monthly int `json:"monthly,omitempty"` + Yearly int `json:"yearly,omitempty"` + } `json:"counters"` +} + // ApplyPolicy returns the snapshots from list that are to be kept and removed -// according to the policy p. list is sorted in the process. -func ApplyPolicy(list Snapshots, p ExpirePolicy) (keep, remove Snapshots) { +// according to the policy p. list is sorted in the process. reasons contains +// the reasons to keep each snapshot, it is in the same order as keep. +func ApplyPolicy(list Snapshots, p ExpirePolicy) (keep, remove Snapshots, reasons []KeepReason) { sort.Sort(list) if p.Empty() { - return list, remove + for _, sn := range list { + reasons = append(reasons, KeepReason{ + Snapshot: sn, + Matches: []string{"policy is empty"}, + }) + } + return list, remove, reasons } if len(list) == 0 { - return list, remove + return list, nil, nil } var buckets = [6]struct { Count int bucker func(d time.Time, nr int) int Last int + reason string }{ - {p.Last, always, -1}, - {p.Hourly, ymdh, -1}, - {p.Daily, ymd, -1}, - {p.Weekly, yw, -1}, - {p.Monthly, ym, -1}, - {p.Yearly, y, -1}, + {p.Last, always, -1, "last snapshot"}, + {p.Hourly, ymdh, -1, "hourly snapshot"}, + {p.Daily, ymd, -1, "daily snapshot"}, + {p.Weekly, yw, -1, "weekly snapshot"}, + {p.Monthly, ym, -1, "monthly snapshot"}, + {p.Yearly, y, -1, "yearly snapshot"}, } latest := findLatestTimestamp(list) for nr, cur := range list { var keepSnap bool + var keepSnapReasons []string // Tags are handled specially as they are not counted. for _, l := range p.Tags { if cur.HasTags(l) { keepSnap = true + keepSnapReasons = append(keepSnapReasons, fmt.Sprintf("has tags %v", l)) } } @@ -168,6 +199,7 @@ func ApplyPolicy(list Snapshots, p ExpirePolicy) (keep, remove Snapshots) { t := latest.AddDate(-p.Within.Years, -p.Within.Months, -p.Within.Days) if cur.Time.After(t) { keepSnap = true + keepSnapReasons = append(keepSnapReasons, fmt.Sprintf("within %v", p.Within)) } } @@ -176,19 +208,32 @@ func ApplyPolicy(list Snapshots, p ExpirePolicy) (keep, remove Snapshots) { if b.Count > 0 { val := b.bucker(cur.Time, nr) if val != b.Last { + debug.Log("keep %v %v, bucker %v, val %v\n", cur.Time, cur.id.Str(), i, val) keepSnap = true buckets[i].Last = val buckets[i].Count-- + keepSnapReasons = append(keepSnapReasons, b.reason) } } } if keepSnap { keep = append(keep, cur) + kr := KeepReason{ + Snapshot: cur, + Matches: keepSnapReasons, + } + kr.Counters.Last = buckets[0].Count + kr.Counters.Hourly = buckets[1].Count + kr.Counters.Daily = buckets[2].Count + kr.Counters.Weekly = buckets[3].Count + kr.Counters.Monthly = buckets[4].Count + kr.Counters.Yearly = buckets[5].Count + reasons = append(reasons, kr) } else { remove = append(remove, cur) } } - return keep, remove + return keep, remove, reasons } diff --git a/internal/restic/snapshot_policy_test.go b/internal/restic/snapshot_policy_test.go index 7ac89e809..a9a80dd79 100644 --- a/internal/restic/snapshot_policy_test.go +++ b/internal/restic/snapshot_policy_test.go @@ -5,10 +5,11 @@ import ( "fmt" "io/ioutil" "path/filepath" - "reflect" "testing" "time" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/restic/restic/internal/restic" ) @@ -52,6 +53,43 @@ func TestExpireSnapshotOps(t *testing.T) { } } +// ApplyPolicyResult is used to marshal/unmarshal the golden files for +// TestApplyPolicy. +type ApplyPolicyResult struct { + Keep restic.Snapshots `json:"keep"` + Reasons []restic.KeepReason `json:"reasons,omitempty"` +} + +func loadGoldenFile(t testing.TB, filename string) (res ApplyPolicyResult) { + buf, err := ioutil.ReadFile(filename) + if err != nil { + t.Fatalf("error loading golden file %v: %v", filename, err) + } + + err = json.Unmarshal(buf, &res) + if err != nil { + t.Fatalf("error unmarshalling golden file %v: %v", filename, err) + } + + return res +} + +func saveGoldenFile(t testing.TB, filename string, keep restic.Snapshots, reasons []restic.KeepReason) { + res := ApplyPolicyResult{ + Keep: keep, + Reasons: reasons, + } + + buf, err := json.MarshalIndent(res, "", " ") + if err != nil { + t.Fatalf("error marshaling result: %v", err) + } + + if err = ioutil.WriteFile(filename, buf, 0644); err != nil { + t.Fatalf("unable to update golden file: %v", err) + } +} + func TestApplyPolicy(t *testing.T) { var testExpireSnapshots = restic.Snapshots{ {Time: parseTimeUTC("2014-09-01 10:20:30")}, @@ -191,10 +229,8 @@ func TestApplyPolicy(t *testing.T) { for i, p := range tests { t.Run("", func(t *testing.T) { - keep, remove := restic.ApplyPolicy(testExpireSnapshots, p) - t.Logf("returned keep %v, remove %v (of %v) expired snapshots for policy %v", - len(keep), len(remove), len(testExpireSnapshots), p) + keep, remove, reasons := restic.ApplyPolicy(testExpireSnapshots, p) if len(keep)+len(remove) != len(testExpireSnapshots) { t.Errorf("len(keep)+len(remove) = %d != len(testExpireSnapshots) = %d", @@ -206,39 +242,26 @@ func TestApplyPolicy(t *testing.T) { p.Sum(), len(keep)) } - for _, sn := range keep { - t.Logf(" keep snapshot at %v %s", sn.Time, sn.Tags) - } - for _, sn := range remove { - t.Logf(" forget snapshot at %v %s", sn.Time, sn.Tags) + if len(keep) != len(reasons) { + t.Errorf("got %d keep reasons for %d snapshots to keep, these must be equal", len(reasons), len(keep)) } goldenFilename := filepath.Join("testdata", fmt.Sprintf("policy_keep_snapshots_%d", i)) if *updateGoldenFiles { - buf, err := json.MarshalIndent(keep, "", " ") - if err != nil { - t.Fatalf("error marshaling result: %v", err) - } - - if err = ioutil.WriteFile(goldenFilename, buf, 0644); err != nil { - t.Fatalf("unable to update golden file: %v", err) - } + saveGoldenFile(t, goldenFilename, keep, reasons) } - buf, err := ioutil.ReadFile(goldenFilename) - if err != nil { - t.Fatalf("error loading golden file %v: %v", goldenFilename, err) + want := loadGoldenFile(t, goldenFilename) + + cmpOpts := cmpopts.IgnoreUnexported(restic.Snapshot{}) + + if !cmp.Equal(want.Keep, keep, cmpOpts) { + t.Error(cmp.Diff(want.Keep, keep, cmpOpts)) } - var want restic.Snapshots - err = json.Unmarshal(buf, &want) - if err != nil { - t.Fatalf("error unmarshalling golden file %v: %v", goldenFilename, err) - } - - if !reflect.DeepEqual(keep, want) { - t.Fatalf("wrong result, want:\n %v\ngot:\n %v", want, keep) + if !cmp.Equal(want.Reasons, reasons, cmpOpts) { + t.Error(cmp.Diff(want.Reasons, reasons, cmpOpts)) } }) } diff --git a/internal/restic/testdata/policy_keep_snapshots_0 b/internal/restic/testdata/policy_keep_snapshots_0 index 875f0e44e..1290b88cf 100644 --- a/internal/restic/testdata/policy_keep_snapshots_0 +++ b/internal/restic/testdata/policy_keep_snapshots_0 @@ -1,581 +1,1782 @@ -[ - { - "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 - }, - { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": [ - "path1", - "path2" - ], - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-15T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30.1Z", - "tree": null, - "paths": null, - "tags": [ - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-12T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-20T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-11T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-09T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-06T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-05T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-02T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-01T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-08T10:20:30Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + }, + { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2014-11-13T10:20:30.1Z", + "tree": null, + "paths": null, + "tags": [ + "bar" + ] + }, + { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-08T10:20:30Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:30:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:28:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:24:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T11:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T10:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T01:03:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T01:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-13T10:20:30.1Z", + "tree": null, + "paths": null, + "tags": [ + "bar" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-08-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "policy is empty" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_1 b/internal/restic/testdata/policy_keep_snapshots_1 index 22e6c2141..060faeff0 100644 --- a/internal/restic/testdata/policy_keep_snapshots_1 +++ b/internal/restic/testdata/policy_keep_snapshots_1 @@ -1,52 +1,184 @@ -[ - { - "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 - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 9 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 8 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 7 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 6 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 5 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 4 + } + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 3 + } + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 2 + } + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 1 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:30:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_10 b/internal/restic/testdata/policy_keep_snapshots_10 index ca08ff08a..1a596e838 100644 --- a/internal/restic/testdata/policy_keep_snapshots_10 +++ b/internal/restic/testdata/policy_keep_snapshots_10 @@ -1,52 +1,187 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08: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-03T07:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-01T07:08:03Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08: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-03T07:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot", + "daily snapshot" + ], + "counters": { + "last": 1, + "daily": 9 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot", + "daily snapshot" + ], + "counters": { + "daily": 8 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 7 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 6 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 5 + } + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 4 + } + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 3 + } + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 2 + } + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 1 + } + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_11 b/internal/restic/testdata/policy_keep_snapshots_11 index d36f97b3c..17586c120 100644 --- a/internal/restic/testdata/policy_keep_snapshots_11 +++ b/internal/restic/testdata/policy_keep_snapshots_11 @@ -1,12 +1,40 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08:03Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "weekly snapshot" + ], + "counters": { + "weekly": 1 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "weekly snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_12 b/internal/restic/testdata/policy_keep_snapshots_12 index 57b4ab846..c0ea0a9b1 100644 --- a/internal/restic/testdata/policy_keep_snapshots_12 +++ b/internal/restic/testdata/policy_keep_snapshots_12 @@ -1,22 +1,76 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-09T21:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-03T07:02:03Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "weekly snapshot" + ], + "counters": { + "weekly": 3 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "weekly snapshot" + ], + "counters": { + "weekly": 2 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "weekly snapshot" + ], + "counters": { + "weekly": 1 + } + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "weekly snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_13 b/internal/restic/testdata/policy_keep_snapshots_13 index 57b4ab846..b52b9a8bc 100644 --- a/internal/restic/testdata/policy_keep_snapshots_13 +++ b/internal/restic/testdata/policy_keep_snapshots_13 @@ -1,22 +1,81 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-09T21:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-03T07:02:03Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot", + "weekly snapshot" + ], + "counters": { + "daily": 2, + "weekly": 3 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot", + "weekly snapshot" + ], + "counters": { + "daily": 1, + "weekly": 2 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot", + "weekly snapshot" + ], + "counters": { + "weekly": 1 + } + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "weekly snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_14 b/internal/restic/testdata/policy_keep_snapshots_14 index 5126b3e01..cd30be6cd 100644 --- a/internal/restic/testdata/policy_keep_snapshots_14 +++ b/internal/restic/testdata/policy_keep_snapshots_14 @@ -1,32 +1,112 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-22T10:20:30Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "monthly": 5 + } + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "monthly": 4 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "monthly": 3 + } + }, + { + "snapshot": { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "monthly": 2 + } + }, + { + "snapshot": { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "monthly": 1 + } + }, + { + "snapshot": { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_15 b/internal/restic/testdata/policy_keep_snapshots_15 index c8fcf1e20..5aa61fe49 100644 --- a/internal/restic/testdata/policy_keep_snapshots_15 +++ b/internal/restic/testdata/policy_keep_snapshots_15 @@ -1,37 +1,135 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08:03Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-22T10:20:30Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot", + "weekly snapshot", + "monthly snapshot" + ], + "counters": { + "daily": 1, + "weekly": 1, + "monthly": 5 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot", + "weekly snapshot" + ], + "counters": { + "monthly": 5 + } + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "monthly": 4 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "monthly": 3 + } + }, + { + "snapshot": { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "monthly": 2 + } + }, + { + "snapshot": { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "monthly": 1 + } + }, + { + "snapshot": { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_16 b/internal/restic/testdata/policy_keep_snapshots_16 index 37a905da0..d0cae94b5 100644 --- a/internal/restic/testdata/policy_keep_snapshots_16 +++ b/internal/restic/testdata/policy_keep_snapshots_16 @@ -1,17 +1,60 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-22T10:20:30Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "yearly snapshot" + ], + "counters": { + "yearly": 9 + } + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "yearly snapshot" + ], + "counters": { + "yearly": 8 + } + }, + { + "snapshot": { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "yearly snapshot" + ], + "counters": { + "yearly": 7 + } + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_17 b/internal/restic/testdata/policy_keep_snapshots_17 index 1398e524f..742b8005b 100644 --- a/internal/restic/testdata/policy_keep_snapshots_17 +++ b/internal/restic/testdata/policy_keep_snapshots_17 @@ -1,52 +1,206 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08: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": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-22T10:20:30Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08: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": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot", + "weekly snapshot", + "monthly snapshot", + "yearly snapshot" + ], + "counters": { + "daily": 6, + "weekly": 1, + "monthly": 2, + "yearly": 9 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot", + "weekly snapshot" + ], + "counters": { + "daily": 5, + "monthly": 2, + "yearly": 9 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 4, + "monthly": 2, + "yearly": 9 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 3, + "monthly": 2, + "yearly": 9 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 2, + "monthly": 2, + "yearly": 9 + } + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 1, + "monthly": 2, + "yearly": 9 + } + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "monthly": 2, + "yearly": 9 + } + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot", + "yearly snapshot" + ], + "counters": { + "monthly": 1, + "yearly": 8 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "monthly snapshot" + ], + "counters": { + "yearly": 8 + } + }, + { + "snapshot": { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "yearly snapshot" + ], + "counters": { + "yearly": 7 + } + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_18 b/internal/restic/testdata/policy_keep_snapshots_18 index de7cea914..cf63c45b8 100644 --- a/internal/restic/testdata/policy_keep_snapshots_18 +++ b/internal/restic/testdata/policy_keep_snapshots_18 @@ -1,153 +1,416 @@ -[ - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": [ - "path1", - "path2" - ], - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2014-11-15T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-12T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-20T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-11T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-09T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-06T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-05T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-02T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-01T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + } + ], + "reasons": [ + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_19 b/internal/restic/testdata/policy_keep_snapshots_19 index 5e0cb619b..81a438313 100644 --- a/internal/restic/testdata/policy_keep_snapshots_19 +++ b/internal/restic/testdata/policy_keep_snapshots_19 @@ -1,41 +1,108 @@ -[ - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": [ - "path1", - "path2" - ], - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2014-11-15T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + } + ], + "reasons": [ + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo, bar]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo, bar]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo, bar]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo, bar]" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_2 b/internal/restic/testdata/policy_keep_snapshots_2 index 867e90ff0..05992b4fb 100644 --- a/internal/restic/testdata/policy_keep_snapshots_2 +++ b/internal/restic/testdata/policy_keep_snapshots_2 @@ -1,77 +1,274 @@ -[ - { - "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 - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 14 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 13 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 12 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 11 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 10 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 9 + } + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 8 + } + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 7 + } + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 6 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:30:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 5 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:28:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 4 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:24:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 3 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 2 + } + }, + { + "snapshot": { + "time": "2016-01-04T11:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 1 + } + }, + { + "snapshot": { + "time": "2016-01-04T10:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_20 b/internal/restic/testdata/policy_keep_snapshots_20 index 51101c49b..a57fcf024 100644 --- a/internal/restic/testdata/policy_keep_snapshots_20 +++ b/internal/restic/testdata/policy_keep_snapshots_20 @@ -1,161 +1,442 @@ -[ - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": [ - "path1", - "path2" - ], - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2014-11-15T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30.1Z", - "tree": null, - "paths": null, - "tags": [ - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-12T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-20T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-11T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-09T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-06T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-05T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-02T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-01T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2014-11-13T10:20:30.1Z", + "tree": null, + "paths": null, + "tags": [ + "bar" + ] + }, + { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + } + ], + "reasons": [ + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo]", + "has tags [bar]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo]", + "has tags [bar]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo]", + "has tags [bar]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "has tags [foo]", + "has tags [bar]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-13T10:20:30.1Z", + "tree": null, + "paths": null, + "tags": [ + "bar" + ] + }, + "matches": [ + "has tags [bar]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "has tags [foo]" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_21 b/internal/restic/testdata/policy_keep_snapshots_21 index 319c9ab1c..1d1cb5b47 100644 --- a/internal/restic/testdata/policy_keep_snapshots_21 +++ b/internal/restic/testdata/policy_keep_snapshots_21 @@ -1,7 +1,22 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1d" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_22 b/internal/restic/testdata/policy_keep_snapshots_22 index 319c9ab1c..f1e195656 100644 --- a/internal/restic/testdata/policy_keep_snapshots_22 +++ b/internal/restic/testdata/policy_keep_snapshots_22 @@ -1,7 +1,22 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 2d" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_23 b/internal/restic/testdata/policy_keep_snapshots_23 index 667fb8b6d..fb38d7347 100644 --- a/internal/restic/testdata/policy_keep_snapshots_23 +++ b/internal/restic/testdata/policy_keep_snapshots_23 @@ -1,17 +1,54 @@ -[ - { - "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 - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 7d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 7d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 7d" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_24 b/internal/restic/testdata/policy_keep_snapshots_24 index 11be139f5..53c6ba912 100644 --- a/internal/restic/testdata/policy_keep_snapshots_24 +++ b/internal/restic/testdata/policy_keep_snapshots_24 @@ -1,97 +1,310 @@ -[ - { - "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 - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:30:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:28:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:24:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T11:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T10:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T01:03:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T01:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_25 b/internal/restic/testdata/policy_keep_snapshots_25 index 11be139f5..e99d505ad 100644 --- a/internal/restic/testdata/policy_keep_snapshots_25 +++ b/internal/restic/testdata/policy_keep_snapshots_25 @@ -1,97 +1,310 @@ -[ - { - "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 - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:30:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:28:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:24:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T11:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T10:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T01:03:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T01:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1m14d" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_26 b/internal/restic/testdata/policy_keep_snapshots_26 index f36ec66b7..61703f8fe 100644 --- a/internal/restic/testdata/policy_keep_snapshots_26 +++ b/internal/restic/testdata/policy_keep_snapshots_26 @@ -1,332 +1,1044 @@ -[ - { - "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 - }, - { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": [ - "path1", - "path2" - ], - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-08T10:20:30Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + }, + { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-08T10:20:30Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:30:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:28:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:24:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T12:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T11:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-04T10:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T01:03:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2016-01-01T01:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + }, + { + "snapshot": { + "time": "2015-08-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "within 1y1m1d" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_3 b/internal/restic/testdata/policy_keep_snapshots_3 index 4c2846221..265e52130 100644 --- a/internal/restic/testdata/policy_keep_snapshots_3 +++ b/internal/restic/testdata/policy_keep_snapshots_3 @@ -1,561 +1,1914 @@ -[ - { - "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 - }, - { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": [ - "path1", - "path2" - ], - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-15T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30.1Z", - "tree": null, - "paths": null, - "tags": [ - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-12T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-20T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-11T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-09T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-06T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-05T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-02T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-01T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-13T10:20:30.1Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + }, + { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2014-11-13T10:20:30.1Z", + "tree": null, + "paths": null, + "tags": [ + "bar" + ] + }, + { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-13T10:20:30.1Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 98 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 97 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 96 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 95 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 94 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 93 + } + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 92 + } + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 91 + } + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 90 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:30:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 89 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:28:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 88 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:24:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 87 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 86 + } + }, + { + "snapshot": { + "time": "2016-01-04T11:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 85 + } + }, + { + "snapshot": { + "time": "2016-01-04T10:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 84 + } + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 83 + } + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 82 + } + }, + { + "snapshot": { + "time": "2016-01-01T01:03:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 81 + } + }, + { + "snapshot": { + "time": "2016-01-01T01:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 80 + } + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 79 + } + }, + { + "snapshot": { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 78 + } + }, + { + "snapshot": { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 77 + } + }, + { + "snapshot": { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 76 + } + }, + { + "snapshot": { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 75 + } + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 74 + } + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 73 + } + }, + { + "snapshot": { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 72 + } + }, + { + "snapshot": { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 71 + } + }, + { + "snapshot": { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 70 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 69 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 68 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 67 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 66 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 65 + } + }, + { + "snapshot": { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 64 + } + }, + { + "snapshot": { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 63 + } + }, + { + "snapshot": { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 62 + } + }, + { + "snapshot": { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 61 + } + }, + { + "snapshot": { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 60 + } + }, + { + "snapshot": { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 59 + } + }, + { + "snapshot": { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 58 + } + }, + { + "snapshot": { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 57 + } + }, + { + "snapshot": { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 56 + } + }, + { + "snapshot": { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 55 + } + }, + { + "snapshot": { + "time": "2015-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 54 + } + }, + { + "snapshot": { + "time": "2015-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 53 + } + }, + { + "snapshot": { + "time": "2015-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 52 + } + }, + { + "snapshot": { + "time": "2015-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 51 + } + }, + { + "snapshot": { + "time": "2015-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 50 + } + }, + { + "snapshot": { + "time": "2015-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 49 + } + }, + { + "snapshot": { + "time": "2015-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 48 + } + }, + { + "snapshot": { + "time": "2015-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 47 + } + }, + { + "snapshot": { + "time": "2015-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 46 + } + }, + { + "snapshot": { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 45 + } + }, + { + "snapshot": { + "time": "2015-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 44 + } + }, + { + "snapshot": { + "time": "2015-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 43 + } + }, + { + "snapshot": { + "time": "2015-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 42 + } + }, + { + "snapshot": { + "time": "2015-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 41 + } + }, + { + "snapshot": { + "time": "2015-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 40 + } + }, + { + "snapshot": { + "time": "2015-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 39 + } + }, + { + "snapshot": { + "time": "2015-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 38 + } + }, + { + "snapshot": { + "time": "2015-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 37 + } + }, + { + "snapshot": { + "time": "2015-08-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 36 + } + }, + { + "snapshot": { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 35 + } + }, + { + "snapshot": { + "time": "2014-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 34 + } + }, + { + "snapshot": { + "time": "2014-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 33 + } + }, + { + "snapshot": { + "time": "2014-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 32 + } + }, + { + "snapshot": { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 31 + } + }, + { + "snapshot": { + "time": "2014-11-13T10:20:30.1Z", + "tree": null, + "paths": null, + "tags": [ + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 30 + } + }, + { + "snapshot": { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 29 + } + }, + { + "snapshot": { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 28 + } + }, + { + "snapshot": { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 27 + } + }, + { + "snapshot": { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 26 + } + }, + { + "snapshot": { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 25 + } + }, + { + "snapshot": { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 24 + } + }, + { + "snapshot": { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 23 + } + }, + { + "snapshot": { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 22 + } + }, + { + "snapshot": { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 21 + } + }, + { + "snapshot": { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 20 + } + }, + { + "snapshot": { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 19 + } + }, + { + "snapshot": { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 18 + } + }, + { + "snapshot": { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 17 + } + }, + { + "snapshot": { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 16 + } + }, + { + "snapshot": { + "time": "2014-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 15 + } + }, + { + "snapshot": { + "time": "2014-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 14 + } + }, + { + "snapshot": { + "time": "2014-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 13 + } + }, + { + "snapshot": { + "time": "2014-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 12 + } + }, + { + "snapshot": { + "time": "2014-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 11 + } + }, + { + "snapshot": { + "time": "2014-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 10 + } + }, + { + "snapshot": { + "time": "2014-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 9 + } + }, + { + "snapshot": { + "time": "2014-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 8 + } + }, + { + "snapshot": { + "time": "2014-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 7 + } + }, + { + "snapshot": { + "time": "2014-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 6 + } + }, + { + "snapshot": { + "time": "2014-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 5 + } + }, + { + "snapshot": { + "time": "2014-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 4 + } + }, + { + "snapshot": { + "time": "2014-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 3 + } + }, + { + "snapshot": { + "time": "2014-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 2 + } + }, + { + "snapshot": { + "time": "2014-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 1 + } + }, + { + "snapshot": { + "time": "2014-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_4 b/internal/restic/testdata/policy_keep_snapshots_4 index 875f0e44e..8657da8c8 100644 --- a/internal/restic/testdata/policy_keep_snapshots_4 +++ b/internal/restic/testdata/policy_keep_snapshots_4 @@ -1,581 +1,1988 @@ -[ - { - "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 - }, - { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": [ - "path1", - "path2" - ], - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-15T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30.1Z", - "tree": null, - "paths": null, - "tags": [ - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-12T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-20T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-11T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-09T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-06T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-05T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-02T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-01T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-08T10:20:30Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + }, + { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-08-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + { + "time": "2014-11-13T10:20:30.1Z", + "tree": null, + "paths": null, + "tags": [ + "bar" + ] + }, + { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + { + "time": "2014-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2014-08-08T10:20:30Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 199 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 198 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 197 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 196 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 195 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 194 + } + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 193 + } + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 192 + } + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 191 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:30:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 190 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:28:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 189 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:24:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 188 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 187 + } + }, + { + "snapshot": { + "time": "2016-01-04T11:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 186 + } + }, + { + "snapshot": { + "time": "2016-01-04T10:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 185 + } + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 184 + } + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 183 + } + }, + { + "snapshot": { + "time": "2016-01-01T01:03:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 182 + } + }, + { + "snapshot": { + "time": "2016-01-01T01:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 181 + } + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 180 + } + }, + { + "snapshot": { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 179 + } + }, + { + "snapshot": { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 178 + } + }, + { + "snapshot": { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 177 + } + }, + { + "snapshot": { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 176 + } + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 175 + } + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 174 + } + }, + { + "snapshot": { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 173 + } + }, + { + "snapshot": { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 172 + } + }, + { + "snapshot": { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 171 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 170 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": [ + "path1", + "path2" + ], + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 169 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 168 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 167 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 166 + } + }, + { + "snapshot": { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 165 + } + }, + { + "snapshot": { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 164 + } + }, + { + "snapshot": { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 163 + } + }, + { + "snapshot": { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 162 + } + }, + { + "snapshot": { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 161 + } + }, + { + "snapshot": { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 160 + } + }, + { + "snapshot": { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 159 + } + }, + { + "snapshot": { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 158 + } + }, + { + "snapshot": { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 157 + } + }, + { + "snapshot": { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 156 + } + }, + { + "snapshot": { + "time": "2015-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 155 + } + }, + { + "snapshot": { + "time": "2015-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 154 + } + }, + { + "snapshot": { + "time": "2015-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 153 + } + }, + { + "snapshot": { + "time": "2015-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 152 + } + }, + { + "snapshot": { + "time": "2015-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 151 + } + }, + { + "snapshot": { + "time": "2015-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 150 + } + }, + { + "snapshot": { + "time": "2015-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 149 + } + }, + { + "snapshot": { + "time": "2015-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 148 + } + }, + { + "snapshot": { + "time": "2015-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 147 + } + }, + { + "snapshot": { + "time": "2015-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 146 + } + }, + { + "snapshot": { + "time": "2015-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 145 + } + }, + { + "snapshot": { + "time": "2015-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 144 + } + }, + { + "snapshot": { + "time": "2015-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 143 + } + }, + { + "snapshot": { + "time": "2015-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 142 + } + }, + { + "snapshot": { + "time": "2015-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 141 + } + }, + { + "snapshot": { + "time": "2015-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 140 + } + }, + { + "snapshot": { + "time": "2015-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 139 + } + }, + { + "snapshot": { + "time": "2015-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 138 + } + }, + { + "snapshot": { + "time": "2015-08-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 137 + } + }, + { + "snapshot": { + "time": "2014-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 136 + } + }, + { + "snapshot": { + "time": "2014-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 135 + } + }, + { + "snapshot": { + "time": "2014-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 134 + } + }, + { + "snapshot": { + "time": "2014-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 133 + } + }, + { + "snapshot": { + "time": "2014-11-15T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo", + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 132 + } + }, + { + "snapshot": { + "time": "2014-11-13T10:20:30.1Z", + "tree": null, + "paths": null, + "tags": [ + "bar" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 131 + } + }, + { + "snapshot": { + "time": "2014-11-13T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 130 + } + }, + { + "snapshot": { + "time": "2014-11-12T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 129 + } + }, + { + "snapshot": { + "time": "2014-11-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 128 + } + }, + { + "snapshot": { + "time": "2014-11-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 127 + } + }, + { + "snapshot": { + "time": "2014-10-22T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 126 + } + }, + { + "snapshot": { + "time": "2014-10-20T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 125 + } + }, + { + "snapshot": { + "time": "2014-10-11T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 124 + } + }, + { + "snapshot": { + "time": "2014-10-10T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 123 + } + }, + { + "snapshot": { + "time": "2014-10-09T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 122 + } + }, + { + "snapshot": { + "time": "2014-10-08T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 121 + } + }, + { + "snapshot": { + "time": "2014-10-06T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 120 + } + }, + { + "snapshot": { + "time": "2014-10-05T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 119 + } + }, + { + "snapshot": { + "time": "2014-10-02T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 118 + } + }, + { + "snapshot": { + "time": "2014-10-01T10:20:30Z", + "tree": null, + "paths": null, + "tags": [ + "foo" + ] + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 117 + } + }, + { + "snapshot": { + "time": "2014-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 116 + } + }, + { + "snapshot": { + "time": "2014-09-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 115 + } + }, + { + "snapshot": { + "time": "2014-09-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 114 + } + }, + { + "snapshot": { + "time": "2014-09-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 113 + } + }, + { + "snapshot": { + "time": "2014-09-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 112 + } + }, + { + "snapshot": { + "time": "2014-09-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 111 + } + }, + { + "snapshot": { + "time": "2014-09-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 110 + } + }, + { + "snapshot": { + "time": "2014-09-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 109 + } + }, + { + "snapshot": { + "time": "2014-09-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 108 + } + }, + { + "snapshot": { + "time": "2014-09-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 107 + } + }, + { + "snapshot": { + "time": "2014-08-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 106 + } + }, + { + "snapshot": { + "time": "2014-08-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 105 + } + }, + { + "snapshot": { + "time": "2014-08-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 104 + } + }, + { + "snapshot": { + "time": "2014-08-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 103 + } + }, + { + "snapshot": { + "time": "2014-08-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 102 + } + }, + { + "snapshot": { + "time": "2014-08-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 101 + } + }, + { + "snapshot": { + "time": "2014-08-13T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 100 + } + }, + { + "snapshot": { + "time": "2014-08-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 99 + } + }, + { + "snapshot": { + "time": "2014-08-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 98 + } + }, + { + "snapshot": { + "time": "2014-08-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 97 + } + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_5 b/internal/restic/testdata/policy_keep_snapshots_5 index dcc09e864..8ed7a3d3e 100644 --- a/internal/restic/testdata/policy_keep_snapshots_5 +++ b/internal/restic/testdata/policy_keep_snapshots_5 @@ -1,102 +1,364 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08: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-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": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30.1Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08: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-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": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 19 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 18 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 17 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 16 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 15 + } + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 14 + } + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 13 + } + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 12 + } + }, + { + "snapshot": { + "time": "2016-01-04T12:30:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 11 + } + }, + { + "snapshot": { + "time": "2016-01-04T11:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 10 + } + }, + { + "snapshot": { + "time": "2016-01-04T10:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 9 + } + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 8 + } + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 7 + } + }, + { + "snapshot": { + "time": "2016-01-01T01:03:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 6 + } + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 5 + } + }, + { + "snapshot": { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 4 + } + }, + { + "snapshot": { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 3 + } + }, + { + "snapshot": { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 2 + } + }, + { + "snapshot": { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": { + "hourly": 1 + } + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "hourly snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_6 b/internal/restic/testdata/policy_keep_snapshots_6 index 69b347d7e..d72ad886d 100644 --- a/internal/restic/testdata/policy_keep_snapshots_6 +++ b/internal/restic/testdata/policy_keep_snapshots_6 @@ -1,17 +1,58 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-09T21:02:03Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 2 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 1 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_7 b/internal/restic/testdata/policy_keep_snapshots_7 index ca08ff08a..6177ebe94 100644 --- a/internal/restic/testdata/policy_keep_snapshots_7 +++ b/internal/restic/testdata/policy_keep_snapshots_7 @@ -1,52 +1,184 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08: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-03T07:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-01T07:08:03Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08: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-03T07:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 9 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 8 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 7 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 6 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 5 + } + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 4 + } + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 3 + } + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 2 + } + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 1 + } + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_8 b/internal/restic/testdata/policy_keep_snapshots_8 index a9656bd3c..d92aa1c20 100644 --- a/internal/restic/testdata/policy_keep_snapshots_8 +++ b/internal/restic/testdata/policy_keep_snapshots_8 @@ -1,152 +1,544 @@ -[ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08: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-03T07:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-01T07:08:03Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-22T10:20:30Z", - "tree": null, - "paths": null - } -] \ No newline at end of file +{ + "keep": [ + { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-12T21:08: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-03T07:02:03Z", + "tree": null, + "paths": null + }, + { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 29 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 28 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 27 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 26 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 25 + } + }, + { + "snapshot": { + "time": "2016-01-06T08:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 24 + } + }, + { + "snapshot": { + "time": "2016-01-05T09:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 23 + } + }, + { + "snapshot": { + "time": "2016-01-04T16:23:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 22 + } + }, + { + "snapshot": { + "time": "2016-01-03T07:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 21 + } + }, + { + "snapshot": { + "time": "2016-01-01T07:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 20 + } + }, + { + "snapshot": { + "time": "2015-11-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 19 + } + }, + { + "snapshot": { + "time": "2015-11-21T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 18 + } + }, + { + "snapshot": { + "time": "2015-11-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 17 + } + }, + { + "snapshot": { + "time": "2015-11-18T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 16 + } + }, + { + "snapshot": { + "time": "2015-11-15T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 15 + } + }, + { + "snapshot": { + "time": "2015-11-13T10:20:30.1Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 14 + } + }, + { + "snapshot": { + "time": "2015-11-12T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 13 + } + }, + { + "snapshot": { + "time": "2015-11-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 12 + } + }, + { + "snapshot": { + "time": "2015-11-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 11 + } + }, + { + "snapshot": { + "time": "2015-10-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 10 + } + }, + { + "snapshot": { + "time": "2015-10-20T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 9 + } + }, + { + "snapshot": { + "time": "2015-10-11T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 8 + } + }, + { + "snapshot": { + "time": "2015-10-10T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 7 + } + }, + { + "snapshot": { + "time": "2015-10-09T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 6 + } + }, + { + "snapshot": { + "time": "2015-10-08T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 5 + } + }, + { + "snapshot": { + "time": "2015-10-06T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 4 + } + }, + { + "snapshot": { + "time": "2015-10-05T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 3 + } + }, + { + "snapshot": { + "time": "2015-10-02T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 2 + } + }, + { + "snapshot": { + "time": "2015-10-01T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": { + "daily": 1 + } + }, + { + "snapshot": { + "time": "2015-09-22T10:20:30Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_9 b/internal/restic/testdata/policy_keep_snapshots_9 index c491b089f..cc33b6f82 100644 --- a/internal/restic/testdata/policy_keep_snapshots_9 +++ b/internal/restic/testdata/policy_keep_snapshots_9 @@ -1,32 +1,120 @@ -[ - { - "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 - } -] \ No newline at end of file +{ + "keep": [ + { + "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 + } + ], + "reasons": [ + { + "snapshot": { + "time": "2016-01-18T12:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot", + "daily snapshot" + ], + "counters": { + "last": 4, + "daily": 4 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:08:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot", + "daily snapshot" + ], + "counters": { + "last": 3, + "daily": 3 + } + }, + { + "snapshot": { + "time": "2016-01-12T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot" + ], + "counters": { + "last": 2, + "daily": 3 + } + }, + { + "snapshot": { + "time": "2016-01-09T21:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot", + "daily snapshot" + ], + "counters": { + "last": 1, + "daily": 2 + } + }, + { + "snapshot": { + "time": "2016-01-08T20:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "last snapshot", + "daily snapshot" + ], + "counters": { + "daily": 1 + } + }, + { + "snapshot": { + "time": "2016-01-07T10:02:03Z", + "tree": null, + "paths": null + }, + "matches": [ + "daily snapshot" + ], + "counters": {} + } + ] +} \ No newline at end of file From 9aa36a37c73f10bc04bd77edf6e1c2c2a606fe39 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 19 Aug 2018 13:02:57 +0200 Subject: [PATCH 3/5] Vendor cmpopts --- Gopkg.lock | 4 +- .../google/go-cmp/cmp/cmpopts/equate.go | 89 +++++++++ .../google/go-cmp/cmp/cmpopts/ignore.go | 145 ++++++++++++++ .../google/go-cmp/cmp/cmpopts/sort.go | 146 ++++++++++++++ .../google/go-cmp/cmp/cmpopts/sort_go17.go | 46 +++++ .../google/go-cmp/cmp/cmpopts/sort_go18.go | 31 +++ .../go-cmp/cmp/cmpopts/struct_filter.go | 182 ++++++++++++++++++ 7 files changed, 642 insertions(+), 1 deletion(-) create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go17.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go18.go create mode 100644 vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go diff --git a/Gopkg.lock b/Gopkg.lock index 6fba8d652..1891a9f94 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -104,10 +104,11 @@ version = "v1.1.0" [[projects]] - digest = "1:2e3c336fc7fde5c984d2841455a658a6d626450b1754a854b3b32e7a8f49a07a" + digest = "1:d2754cafcab0d22c13541618a8029a70a8959eb3525ff201fe971637e2274cd0" name = "github.com/google/go-cmp" packages = [ "cmp", + "cmp/cmpopts", "cmp/internal/diff", "cmp/internal/function", "cmp/internal/value", @@ -449,6 +450,7 @@ "github.com/cenkalti/backoff", "github.com/elithrar/simple-scrypt", "github.com/google/go-cmp/cmp", + "github.com/google/go-cmp/cmp/cmpopts", "github.com/juju/ratelimit", "github.com/kurin/blazer/b2", "github.com/mattn/go-isatty", diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go new file mode 100644 index 000000000..41bbddc61 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go @@ -0,0 +1,89 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// Package cmpopts provides common options for the cmp package. +package cmpopts + +import ( + "math" + "reflect" + + "github.com/google/go-cmp/cmp" +) + +func equateAlways(_, _ interface{}) bool { return true } + +// EquateEmpty returns a Comparer option that determines all maps and slices +// with a length of zero to be equal, regardless of whether they are nil. +// +// EquateEmpty can be used in conjunction with SortSlices and SortMaps. +func EquateEmpty() cmp.Option { + return cmp.FilterValues(isEmpty, cmp.Comparer(equateAlways)) +} + +func isEmpty(x, y interface{}) bool { + vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) + return (x != nil && y != nil && vx.Type() == vy.Type()) && + (vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) && + (vx.Len() == 0 && vy.Len() == 0) +} + +// EquateApprox returns a Comparer option that determines float32 or float64 +// values to be equal if they are within a relative fraction or absolute margin. +// This option is not used when either x or y is NaN or infinite. +// +// The fraction determines that the difference of two values must be within the +// smaller fraction of the two values, while the margin determines that the two +// values must be within some absolute margin. +// To express only a fraction or only a margin, use 0 for the other parameter. +// The fraction and margin must be non-negative. +// +// The mathematical expression used is equivalent to: +// |x-y| ≤ max(fraction*min(|x|, |y|), margin) +// +// EquateApprox can be used in conjunction with EquateNaNs. +func EquateApprox(fraction, margin float64) cmp.Option { + if margin < 0 || fraction < 0 || math.IsNaN(margin) || math.IsNaN(fraction) { + panic("margin or fraction must be a non-negative number") + } + a := approximator{fraction, margin} + return cmp.Options{ + cmp.FilterValues(areRealF64s, cmp.Comparer(a.compareF64)), + cmp.FilterValues(areRealF32s, cmp.Comparer(a.compareF32)), + } +} + +type approximator struct{ frac, marg float64 } + +func areRealF64s(x, y float64) bool { + return !math.IsNaN(x) && !math.IsNaN(y) && !math.IsInf(x, 0) && !math.IsInf(y, 0) +} +func areRealF32s(x, y float32) bool { + return areRealF64s(float64(x), float64(y)) +} +func (a approximator) compareF64(x, y float64) bool { + relMarg := a.frac * math.Min(math.Abs(x), math.Abs(y)) + return math.Abs(x-y) <= math.Max(a.marg, relMarg) +} +func (a approximator) compareF32(x, y float32) bool { + return a.compareF64(float64(x), float64(y)) +} + +// EquateNaNs returns a Comparer option that determines float32 and float64 +// NaN values to be equal. +// +// EquateNaNs can be used in conjunction with EquateApprox. +func EquateNaNs() cmp.Option { + return cmp.Options{ + cmp.FilterValues(areNaNsF64s, cmp.Comparer(equateAlways)), + cmp.FilterValues(areNaNsF32s, cmp.Comparer(equateAlways)), + } +} + +func areNaNsF64s(x, y float64) bool { + return math.IsNaN(x) && math.IsNaN(y) +} +func areNaNsF32s(x, y float32) bool { + return areNaNsF64s(float64(x), float64(y)) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go new file mode 100644 index 000000000..e86554b92 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go @@ -0,0 +1,145 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmpopts + +import ( + "fmt" + "reflect" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp" +) + +// IgnoreFields returns an Option that ignores exported fields of the +// given names on a single struct type. +// The struct type is specified by passing in a value of that type. +// +// The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a +// specific sub-field that is embedded or nested within the parent struct. +// +// This does not handle unexported fields; use IgnoreUnexported instead. +func IgnoreFields(typ interface{}, names ...string) cmp.Option { + sf := newStructFilter(typ, names...) + return cmp.FilterPath(sf.filter, cmp.Ignore()) +} + +// IgnoreTypes returns an Option that ignores all values assignable to +// certain types, which are specified by passing in a value of each type. +func IgnoreTypes(typs ...interface{}) cmp.Option { + tf := newTypeFilter(typs...) + return cmp.FilterPath(tf.filter, cmp.Ignore()) +} + +type typeFilter []reflect.Type + +func newTypeFilter(typs ...interface{}) (tf typeFilter) { + for _, typ := range typs { + t := reflect.TypeOf(typ) + if t == nil { + // This occurs if someone tries to pass in sync.Locker(nil) + panic("cannot determine type; consider using IgnoreInterfaces") + } + tf = append(tf, t) + } + return tf +} +func (tf typeFilter) filter(p cmp.Path) bool { + if len(p) < 1 { + return false + } + t := p.Last().Type() + for _, ti := range tf { + if t.AssignableTo(ti) { + return true + } + } + return false +} + +// IgnoreInterfaces returns an Option that ignores all values or references of +// values assignable to certain interface types. These interfaces are specified +// by passing in an anonymous struct with the interface types embedded in it. +// For example, to ignore sync.Locker, pass in struct{sync.Locker}{}. +func IgnoreInterfaces(ifaces interface{}) cmp.Option { + tf := newIfaceFilter(ifaces) + return cmp.FilterPath(tf.filter, cmp.Ignore()) +} + +type ifaceFilter []reflect.Type + +func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) { + t := reflect.TypeOf(ifaces) + if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct { + panic("input must be an anonymous struct") + } + for i := 0; i < t.NumField(); i++ { + fi := t.Field(i) + switch { + case !fi.Anonymous: + panic("struct cannot have named fields") + case fi.Type.Kind() != reflect.Interface: + panic("embedded field must be an interface type") + case fi.Type.NumMethod() == 0: + // This matches everything; why would you ever want this? + panic("cannot ignore empty interface") + default: + tf = append(tf, fi.Type) + } + } + return tf +} +func (tf ifaceFilter) filter(p cmp.Path) bool { + if len(p) < 1 { + return false + } + t := p.Last().Type() + for _, ti := range tf { + if t.AssignableTo(ti) { + return true + } + if t.Kind() != reflect.Ptr && reflect.PtrTo(t).AssignableTo(ti) { + return true + } + } + return false +} + +// IgnoreUnexported returns an Option that only ignores the immediate unexported +// fields of a struct, including anonymous fields of unexported types. +// In particular, unexported fields within the struct's exported fields +// of struct types, including anonymous fields, will not be ignored unless the +// type of the field itself is also passed to IgnoreUnexported. +func IgnoreUnexported(typs ...interface{}) cmp.Option { + ux := newUnexportedFilter(typs...) + return cmp.FilterPath(ux.filter, cmp.Ignore()) +} + +type unexportedFilter struct{ m map[reflect.Type]bool } + +func newUnexportedFilter(typs ...interface{}) unexportedFilter { + ux := unexportedFilter{m: make(map[reflect.Type]bool)} + for _, typ := range typs { + t := reflect.TypeOf(typ) + if t == nil || t.Kind() != reflect.Struct { + panic(fmt.Sprintf("invalid struct type: %T", typ)) + } + ux.m[t] = true + } + return ux +} +func (xf unexportedFilter) filter(p cmp.Path) bool { + sf, ok := p.Index(-1).(cmp.StructField) + if !ok { + return false + } + return xf.m[p.Index(-2).Type()] && !isExported(sf.Name()) +} + +// isExported reports whether the identifier is exported. +func isExported(id string) bool { + r, _ := utf8.DecodeRuneInString(id) + return unicode.IsUpper(r) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go new file mode 100644 index 000000000..da17d7469 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go @@ -0,0 +1,146 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmpopts + +import ( + "fmt" + "reflect" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/internal/function" +) + +// SortSlices returns a Transformer option that sorts all []V. +// The less function must be of the form "func(T, T) bool" which is used to +// sort any slice with element type V that is assignable to T. +// +// The less function must be: +// • Deterministic: less(x, y) == less(x, y) +// • Irreflexive: !less(x, x) +// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z) +// +// The less function does not have to be "total". That is, if !less(x, y) and +// !less(y, x) for two elements x and y, their relative order is maintained. +// +// SortSlices can be used in conjunction with EquateEmpty. +func SortSlices(less interface{}) cmp.Option { + vf := reflect.ValueOf(less) + if !function.IsType(vf.Type(), function.Less) || vf.IsNil() { + panic(fmt.Sprintf("invalid less function: %T", less)) + } + ss := sliceSorter{vf.Type().In(0), vf} + return cmp.FilterValues(ss.filter, cmp.Transformer("Sort", ss.sort)) +} + +type sliceSorter struct { + in reflect.Type // T + fnc reflect.Value // func(T, T) bool +} + +func (ss sliceSorter) filter(x, y interface{}) bool { + vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) + if !(x != nil && y != nil && vx.Type() == vy.Type()) || + !(vx.Kind() == reflect.Slice && vx.Type().Elem().AssignableTo(ss.in)) || + (vx.Len() <= 1 && vy.Len() <= 1) { + return false + } + // Check whether the slices are already sorted to avoid an infinite + // recursion cycle applying the same transform to itself. + ok1 := sliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) }) + ok2 := sliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) }) + return !ok1 || !ok2 +} +func (ss sliceSorter) sort(x interface{}) interface{} { + src := reflect.ValueOf(x) + dst := reflect.MakeSlice(src.Type(), src.Len(), src.Len()) + for i := 0; i < src.Len(); i++ { + dst.Index(i).Set(src.Index(i)) + } + sortSliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) }) + ss.checkSort(dst) + return dst.Interface() +} +func (ss sliceSorter) checkSort(v reflect.Value) { + start := -1 // Start of a sequence of equal elements. + for i := 1; i < v.Len(); i++ { + if ss.less(v, i-1, i) { + // Check that first and last elements in v[start:i] are equal. + if start >= 0 && (ss.less(v, start, i-1) || ss.less(v, i-1, start)) { + panic(fmt.Sprintf("incomparable values detected: want equal elements: %v", v.Slice(start, i))) + } + start = -1 + } else if start == -1 { + start = i + } + } +} +func (ss sliceSorter) less(v reflect.Value, i, j int) bool { + vx, vy := v.Index(i), v.Index(j) + return ss.fnc.Call([]reflect.Value{vx, vy})[0].Bool() +} + +// SortMaps returns a Transformer option that flattens map[K]V types to be a +// sorted []struct{K, V}. The less function must be of the form +// "func(T, T) bool" which is used to sort any map with key K that is +// assignable to T. +// +// Flattening the map into a slice has the property that cmp.Equal is able to +// use Comparers on K or the K.Equal method if it exists. +// +// The less function must be: +// • Deterministic: less(x, y) == less(x, y) +// • Irreflexive: !less(x, x) +// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z) +// • Total: if x != y, then either less(x, y) or less(y, x) +// +// SortMaps can be used in conjunction with EquateEmpty. +func SortMaps(less interface{}) cmp.Option { + vf := reflect.ValueOf(less) + if !function.IsType(vf.Type(), function.Less) || vf.IsNil() { + panic(fmt.Sprintf("invalid less function: %T", less)) + } + ms := mapSorter{vf.Type().In(0), vf} + return cmp.FilterValues(ms.filter, cmp.Transformer("Sort", ms.sort)) +} + +type mapSorter struct { + in reflect.Type // T + fnc reflect.Value // func(T, T) bool +} + +func (ms mapSorter) filter(x, y interface{}) bool { + vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) + return (x != nil && y != nil && vx.Type() == vy.Type()) && + (vx.Kind() == reflect.Map && vx.Type().Key().AssignableTo(ms.in)) && + (vx.Len() != 0 || vy.Len() != 0) +} +func (ms mapSorter) sort(x interface{}) interface{} { + src := reflect.ValueOf(x) + outType := mapEntryType(src.Type()) + dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len()) + for i, k := range src.MapKeys() { + v := reflect.New(outType).Elem() + v.Field(0).Set(k) + v.Field(1).Set(src.MapIndex(k)) + dst.Index(i).Set(v) + } + sortSlice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) }) + ms.checkSort(dst) + return dst.Interface() +} +func (ms mapSorter) checkSort(v reflect.Value) { + for i := 1; i < v.Len(); i++ { + if !ms.less(v, i-1, i) { + panic(fmt.Sprintf("partial order detected: want %v < %v", v.Index(i-1), v.Index(i))) + } + } +} +func (ms mapSorter) less(v reflect.Value, i, j int) bool { + vx, vy := v.Index(i).Field(0), v.Index(j).Field(0) + if !hasReflectStructOf { + vx, vy = vx.Elem(), vy.Elem() + } + return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool() +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go17.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go17.go new file mode 100644 index 000000000..839b88ca4 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go17.go @@ -0,0 +1,46 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build !go1.8 + +package cmpopts + +import ( + "reflect" + "sort" +) + +const hasReflectStructOf = false + +func mapEntryType(reflect.Type) reflect.Type { + return reflect.TypeOf(struct{ K, V interface{} }{}) +} + +func sliceIsSorted(slice interface{}, less func(i, j int) bool) bool { + return sort.IsSorted(reflectSliceSorter{reflect.ValueOf(slice), less}) +} +func sortSlice(slice interface{}, less func(i, j int) bool) { + sort.Sort(reflectSliceSorter{reflect.ValueOf(slice), less}) +} +func sortSliceStable(slice interface{}, less func(i, j int) bool) { + sort.Stable(reflectSliceSorter{reflect.ValueOf(slice), less}) +} + +type reflectSliceSorter struct { + slice reflect.Value + less func(i, j int) bool +} + +func (ss reflectSliceSorter) Len() int { + return ss.slice.Len() +} +func (ss reflectSliceSorter) Less(i, j int) bool { + return ss.less(i, j) +} +func (ss reflectSliceSorter) Swap(i, j int) { + vi := ss.slice.Index(i).Interface() + vj := ss.slice.Index(j).Interface() + ss.slice.Index(i).Set(reflect.ValueOf(vj)) + ss.slice.Index(j).Set(reflect.ValueOf(vi)) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go18.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go18.go new file mode 100644 index 000000000..8a59c0d38 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort_go18.go @@ -0,0 +1,31 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +// +build go1.8 + +package cmpopts + +import ( + "reflect" + "sort" +) + +const hasReflectStructOf = true + +func mapEntryType(t reflect.Type) reflect.Type { + return reflect.StructOf([]reflect.StructField{ + {Name: "K", Type: t.Key()}, + {Name: "V", Type: t.Elem()}, + }) +} + +func sliceIsSorted(slice interface{}, less func(i, j int) bool) bool { + return sort.SliceIsSorted(slice, less) +} +func sortSlice(slice interface{}, less func(i, j int) bool) { + sort.Slice(slice, less) +} +func sortSliceStable(slice interface{}, less func(i, j int) bool) { + sort.SliceStable(slice, less) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go new file mode 100644 index 000000000..97f707983 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go @@ -0,0 +1,182 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmpopts + +import ( + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp" +) + +// filterField returns a new Option where opt is only evaluated on paths that +// include a specific exported field on a single struct type. +// The struct type is specified by passing in a value of that type. +// +// The name may be a dot-delimited string (e.g., "Foo.Bar") to select a +// specific sub-field that is embedded or nested within the parent struct. +func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option { + // TODO: This is currently unexported over concerns of how helper filters + // can be composed together easily. + // TODO: Add tests for FilterField. + + sf := newStructFilter(typ, name) + return cmp.FilterPath(sf.filter, opt) +} + +type structFilter struct { + t reflect.Type // The root struct type to match on + ft fieldTree // Tree of fields to match on +} + +func newStructFilter(typ interface{}, names ...string) structFilter { + // TODO: Perhaps allow * as a special identifier to allow ignoring any + // number of path steps until the next field match? + // This could be useful when a concrete struct gets transformed into + // an anonymous struct where it is not possible to specify that by type, + // but the transformer happens to provide guarantees about the names of + // the transformed fields. + + t := reflect.TypeOf(typ) + if t == nil || t.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T must be a struct", typ)) + } + var ft fieldTree + for _, name := range names { + cname, err := canonicalName(t, name) + if err != nil { + panic(fmt.Sprintf("%s: %v", strings.Join(cname, "."), err)) + } + ft.insert(cname) + } + return structFilter{t, ft} +} + +func (sf structFilter) filter(p cmp.Path) bool { + for i, ps := range p { + if ps.Type().AssignableTo(sf.t) && sf.ft.matchPrefix(p[i+1:]) { + return true + } + } + return false +} + +// fieldTree represents a set of dot-separated identifiers. +// +// For example, inserting the following selectors: +// Foo +// Foo.Bar.Baz +// Foo.Buzz +// Nuka.Cola.Quantum +// +// Results in a tree of the form: +// {sub: { +// "Foo": {ok: true, sub: { +// "Bar": {sub: { +// "Baz": {ok: true}, +// }}, +// "Buzz": {ok: true}, +// }}, +// "Nuka": {sub: { +// "Cola": {sub: { +// "Quantum": {ok: true}, +// }}, +// }}, +// }} +type fieldTree struct { + ok bool // Whether this is a specified node + sub map[string]fieldTree // The sub-tree of fields under this node +} + +// insert inserts a sequence of field accesses into the tree. +func (ft *fieldTree) insert(cname []string) { + if ft.sub == nil { + ft.sub = make(map[string]fieldTree) + } + if len(cname) == 0 { + ft.ok = true + return + } + sub := ft.sub[cname[0]] + sub.insert(cname[1:]) + ft.sub[cname[0]] = sub +} + +// matchPrefix reports whether any selector in the fieldTree matches +// the start of path p. +func (ft fieldTree) matchPrefix(p cmp.Path) bool { + for _, ps := range p { + switch ps := ps.(type) { + case cmp.StructField: + ft = ft.sub[ps.Name()] + if ft.ok { + return true + } + if len(ft.sub) == 0 { + return false + } + case cmp.Indirect: + default: + return false + } + } + return false +} + +// canonicalName returns a list of identifiers where any struct field access +// through an embedded field is expanded to include the names of the embedded +// types themselves. +// +// For example, suppose field "Foo" is not directly in the parent struct, +// but actually from an embedded struct of type "Bar". Then, the canonical name +// of "Foo" is actually "Bar.Foo". +// +// Suppose field "Foo" is not directly in the parent struct, but actually +// a field in two different embedded structs of types "Bar" and "Baz". +// Then the selector "Foo" causes a panic since it is ambiguous which one it +// refers to. The user must specify either "Bar.Foo" or "Baz.Foo". +func canonicalName(t reflect.Type, sel string) ([]string, error) { + var name string + sel = strings.TrimPrefix(sel, ".") + if sel == "" { + return nil, fmt.Errorf("name must not be empty") + } + if i := strings.IndexByte(sel, '.'); i < 0 { + name, sel = sel, "" + } else { + name, sel = sel[:i], sel[i:] + } + + // Type must be a struct or pointer to struct. + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() != reflect.Struct { + return nil, fmt.Errorf("%v must be a struct", t) + } + + // Find the canonical name for this current field name. + // If the field exists in an embedded struct, then it will be expanded. + if !isExported(name) { + // Disallow unexported fields: + // * To discourage people from actually touching unexported fields + // * FieldByName is buggy (https://golang.org/issue/4876) + return []string{name}, fmt.Errorf("name must be exported") + } + sf, ok := t.FieldByName(name) + if !ok { + return []string{name}, fmt.Errorf("does not exist") + } + var ss []string + for i := range sf.Index { + ss = append(ss, t.FieldByIndex(sf.Index[:i+1]).Name) + } + if sel == "" { + return ss, nil + } + ssPost, err := canonicalName(sf.Type, sel) + return append(ss, ssPost...), err +} From 76387b6cd05581b24627551993b18585bc96a359 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 19 Aug 2018 21:31:53 +0200 Subject: [PATCH 4/5] Remove old text table implementation --- cmd/restic/cmd_cache.go | 17 ++++++--- cmd/restic/cmd_key.go | 78 +++++++++++++++-------------------------- cmd/restic/global.go | 3 ++ cmd/restic/table.go | 63 --------------------------------- 4 files changed, 45 insertions(+), 116 deletions(-) delete mode 100644 cmd/restic/table.go diff --git a/cmd/restic/cmd_cache.go b/cmd/restic/cmd_cache.go index 1f19a40f2..f206dc845 100644 --- a/cmd/restic/cmd_cache.go +++ b/cmd/restic/cmd_cache.go @@ -9,6 +9,7 @@ import ( "github.com/restic/restic/internal/cache" "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/fs" + "github.com/restic/restic/internal/ui/table" "github.com/spf13/cobra" ) @@ -85,9 +86,17 @@ func runCache(opts CacheOptions, gopts GlobalOptions, args []string) error { return nil } - tab := NewTable() - tab.Header = fmt.Sprintf("%-14s %-16s %s", "Repository ID", "Last Used", "Old") - tab.RowFormat = "%-14s %-16s %s" + tab := table.New() + + type data struct { + ID string + Last string + Old string + } + + tab.AddColumn("Repo ID", "{{ .ID }}") + tab.AddColumn("Last Used", "{{ .Last }}") + tab.AddColumn("Old", "{{ .Old }}") dirs, err := cache.All(cachedir) if err != nil { @@ -109,7 +118,7 @@ func runCache(opts CacheOptions, gopts GlobalOptions, args []string) error { old = "yes" } - tab.Rows = append(tab.Rows, []interface{}{ + tab.AddRow(data{ entry.Name()[:10], fmt.Sprintf("%d days ago", uint(time.Since(entry.ModTime()).Hours()/24)), old, diff --git a/cmd/restic/cmd_key.go b/cmd/restic/cmd_key.go index 0c5a7e9a0..900b29d50 100644 --- a/cmd/restic/cmd_key.go +++ b/cmd/restic/cmd_key.go @@ -3,7 +3,6 @@ package main import ( "context" "encoding/json" - "fmt" "io/ioutil" "os" "strings" @@ -11,6 +10,7 @@ import ( "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/repository" "github.com/restic/restic/internal/restic" + "github.com/restic/restic/internal/ui/table" "github.com/spf13/cobra" ) @@ -36,53 +36,18 @@ func init() { flags.StringVarP(&newPasswordFile, "new-password-file", "", "", "the file from which to load a new password") } -type keyInfo struct { - Current bool `json:"current"` - ID string `json:"id"` - UserName string `json:"userName"` - HostName string `json:"hostName"` - Created string `json:"created"` -} - -func (ki keyInfo) CurrentStr() string { - if ki.Current { - return "*" - } - return " " -} - func listKeys(ctx context.Context, s *repository.Repository, gopts GlobalOptions) error { - var ( - appendKey func(keyInfo) - printKeys func() error - ) - - switch gopts.JSON { - case true: - var keys []keyInfo - - appendKey = func(key keyInfo) { - keys = append(keys, key) - } - - printKeys = func() error { - return json.NewEncoder(gopts.stdout).Encode(keys) - } - default: - tab := NewTable() - tab.Header = fmt.Sprintf(" %-10s %-10s %-10s %s", "ID", "User", "Host", "Created") - tab.RowFormat = "%s%-10s %-10s %-10s %s" - - appendKey = func(key keyInfo) { - tab.Rows = append(tab.Rows, []interface{}{key.CurrentStr(), key.ID, key.UserName, key.HostName, key.Created}) - } - - printKeys = func() error { - return tab.Write(globalOptions.stdout) - } + type keyInfo struct { + Current bool `json:"current"` + ID string `json:"id"` + UserName string `json:"userName"` + HostName string `json:"hostName"` + Created string `json:"created"` } - if err := s.List(ctx, restic.KeyFile, func(id restic.ID, size int64) error { + var keys []keyInfo + + err := s.List(ctx, restic.KeyFile, func(id restic.ID, size int64) error { k, err := repository.LoadKey(ctx, s, id.String()) if err != nil { Warnf("LoadKey() failed: %v\n", err) @@ -97,14 +62,29 @@ func listKeys(ctx context.Context, s *repository.Repository, gopts GlobalOptions Created: k.Created.Format(TimeFormat), } - appendKey(key) - + keys = append(keys, key) return nil - }); err != nil { + }) + + if err != nil { return err } - return printKeys() + if gopts.JSON { + return json.NewEncoder(globalOptions.stdout).Encode(keys) + } + + tab := table.New() + tab.AddColumn(" ID", "{{if .Current}}*{{else}} {{end}}{{ .ID }}") + tab.AddColumn("User", "{{ .UserName }}") + tab.AddColumn("Host", "{{ .HostName }}") + tab.AddColumn("Created", "{{ .Created }}") + + for _, key := range keys { + tab.AddRow(key) + } + + return tab.Write(globalOptions.stdout) } // testKeyNewPassword is used to set a new password during integration testing. diff --git a/cmd/restic/global.go b/cmd/restic/global.go index d35b6ba4f..e288fb2da 100644 --- a/cmd/restic/global.go +++ b/cmd/restic/global.go @@ -38,6 +38,9 @@ import ( var version = "0.9.2-dev (compiled manually)" +// TimeFormat is the format used for all timestamps printed by restic. +const TimeFormat = "2006-01-02 15:04:05" + // GlobalOptions hold all global options for restic. type GlobalOptions struct { Repo string diff --git a/cmd/restic/table.go b/cmd/restic/table.go deleted file mode 100644 index b2fa772f8..000000000 --- a/cmd/restic/table.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "fmt" - "io" - "strings" -) - -// Table contains data for a table to be printed. -type Table struct { - Header string - Rows [][]interface{} - Footer string - - RowFormat string -} - -// NewTable initializes a new Table. -func NewTable() Table { - return Table{ - Rows: [][]interface{}{}, - } -} - -func (t Table) printSeparationLine(w io.Writer) error { - _, err := fmt.Fprintln(w, strings.Repeat("-", 70)) - return err -} - -// Write prints the table to w. -func (t Table) Write(w io.Writer) error { - _, err := fmt.Fprintln(w, t.Header) - if err != nil { - return err - } - - err = t.printSeparationLine(w) - if err != nil { - return err - } - - for _, row := range t.Rows { - _, err = fmt.Fprintf(w, t.RowFormat+"\n", row...) - if err != nil { - return err - } - } - - err = t.printSeparationLine(w) - if err != nil { - return err - } - - _, err = fmt.Fprintln(w, t.Footer) - if err != nil { - return err - } - - return nil -} - -// TimeFormat is the format used for all timestamps printed by restic. -const TimeFormat = "2006-01-02 15:04:05" From 5937b5b3552c7a4ec844e33997c8e18c14d3a290 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 20 Aug 2018 21:55:12 +0200 Subject: [PATCH 5/5] Add entry to changelog --- changelog/unreleased/pull-1876 | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 changelog/unreleased/pull-1876 diff --git a/changelog/unreleased/pull-1876 b/changelog/unreleased/pull-1876 new file mode 100644 index 000000000..2fb1a8ea8 --- /dev/null +++ b/changelog/unreleased/pull-1876 @@ -0,0 +1,7 @@ +Enhancement: Display reason why forget keeps snapshots + +We've added a column to the list of snapshots `forget` keeps which details the +reasons to keep a particuliar snapshot. This makes debugging policies for +forget much easier. Please remember to always try things out with `--dry-run`! + +https://github.com/restic/restic/pull/1876