cmd/snapshots: Add option to limit snapshots list

This patch adds a `--latest` option to limit snapshots list to the n
last snapshots. It is very similar to the `--last` one but does not
limit to one entry. It also deprecates the `--last` flag usage in
favor of `--latest 1`

Output example:

    $ restic snapshots --latest 2
    repository 0d3eb989 opened successfully, password is correct
    ID        Time                 Host        Tags        Paths
    ------------------------------------------------------------
    5a33bdcc  2020-12-14 12:30:00  local                   /home
    73887d8e  2020-12-15 12:30:00  local                   /home
    ------------------------------------------------------------
    2 snapshots

Signed-off-by: Sébastien Gross <seb•ɑƬ•chezwam•ɖɵʈ•org>
This commit is contained in:
Sébastien Gross 2020-12-16 10:09:03 +01:00 committed by Michael Eischer
parent 01261770bb
commit 2a92b68e65
2 changed files with 30 additions and 9 deletions

View File

@ -0,0 +1,9 @@
Enhancement: Allow limiting the snapshots list
The `--last` option allowed limiting the output of the `snapshots`
command to the latest snapshot for each host. The new `--latest n`
option allows limiting the output to the latest `n` snapshots.
This change deprecate `--last` in favour of `--latest 1`
https://github.com/restic/restic/pull/3167

View File

@ -36,7 +36,8 @@ type SnapshotOptions struct {
Tags restic.TagLists Tags restic.TagLists
Paths []string Paths []string
Compact bool Compact bool
Last bool Last bool // This option should be removed in favour of Latest.
Latest int
GroupBy string GroupBy string
} }
@ -51,6 +52,12 @@ func init() {
f.StringArrayVar(&snapshotOptions.Paths, "path", nil, "only consider snapshots for this `path` (can be specified multiple times)") f.StringArrayVar(&snapshotOptions.Paths, "path", nil, "only consider snapshots for this `path` (can be specified multiple times)")
f.BoolVarP(&snapshotOptions.Compact, "compact", "c", false, "use compact output format") f.BoolVarP(&snapshotOptions.Compact, "compact", "c", false, "use compact output format")
f.BoolVar(&snapshotOptions.Last, "last", false, "only show the last snapshot for each host and path") f.BoolVar(&snapshotOptions.Last, "last", false, "only show the last snapshot for each host and path")
err := f.MarkDeprecated("last", "use --latest 1")
if err != nil {
// MarkDeprecated only returns an error when the flag is not found
panic(err)
}
f.IntVar(&snapshotOptions.Latest, "latest", 0, "only show the last `n` snapshots for each host and path")
f.StringVarP(&snapshotOptions.GroupBy, "group-by", "g", "", "string for grouping snapshots by host,paths,tags") f.StringVarP(&snapshotOptions.GroupBy, "group-by", "g", "", "string for grouping snapshots by host,paths,tags")
} }
@ -82,7 +89,11 @@ func runSnapshots(opts SnapshotOptions, gopts GlobalOptions, args []string) erro
for k, list := range snapshotGroups { for k, list := range snapshotGroups {
if opts.Last { if opts.Last {
list = FilterLastSnapshots(list) // This branch should be removed in the same time
// that --last.
list = FilterLastestSnapshots(list, 1)
} else if opts.Latest > 0 {
list = FilterLastestSnapshots(list, opts.Latest)
} }
sort.Sort(sort.Reverse(list)) sort.Sort(sort.Reverse(list))
snapshotGroups[k] = list snapshotGroups[k] = list
@ -125,21 +136,22 @@ func newFilterLastSnapshotsKey(sn *restic.Snapshot) filterLastSnapshotsKey {
return filterLastSnapshotsKey{sn.Hostname, strings.Join(paths, "|")} return filterLastSnapshotsKey{sn.Hostname, strings.Join(paths, "|")}
} }
// FilterLastSnapshots filters a list of snapshots to only return the last // FilterLastestSnapshots filters a list of snapshots to only return
// entry for each hostname and path. If the snapshot contains multiple paths, // the limit last entries for each hostname and path. If the snapshot
// they will be joined and treated as one item. // contains multiple paths, they will be joined and treated as one
func FilterLastSnapshots(list restic.Snapshots) restic.Snapshots { // item.
func FilterLastestSnapshots(list restic.Snapshots, limit int) restic.Snapshots {
// Sort the snapshots so that the newer ones are listed first // Sort the snapshots so that the newer ones are listed first
sort.SliceStable(list, func(i, j int) bool { sort.SliceStable(list, func(i, j int) bool {
return list[i].Time.After(list[j].Time) return list[i].Time.After(list[j].Time)
}) })
var results restic.Snapshots var results restic.Snapshots
seen := make(map[filterLastSnapshotsKey]bool) seen := make(map[filterLastSnapshotsKey]int)
for _, sn := range list { for _, sn := range list {
key := newFilterLastSnapshotsKey(sn) key := newFilterLastSnapshotsKey(sn)
if !seen[key] { if seen[key] < limit {
seen[key] = true seen[key]++
results = append(results, sn) results = append(results, sn)
} }
} }