2
2
mirror of https://github.com/octoleo/restic.git synced 2024-06-01 08:30:49 +00:00

Merge pull request #2185 from d3zd3z/json-forget

Json forget
This commit is contained in:
Alexander Neumann 2019-04-13 14:23:32 +02:00
commit 78a3ffcfb9
3 changed files with 95 additions and 6 deletions

View File

@ -0,0 +1,8 @@
Enhancement: Add --json support to forget command
The forget command now supports the --json argument, outputting the
information about what is (or would-be) kept and removed from the
repository.
https://github.com/restic/restic/issues/2184
https://github.com/restic/restic/pull/2185

View File

@ -3,6 +3,7 @@ package main
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"io"
"sort" "sort"
"strings" "strings"
@ -182,7 +183,11 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
} }
if !policy.Empty() { if !policy.Empty() {
Verbosef("Applying Policy: %v\n", policy) if !gopts.JSON {
Verbosef("Applying Policy: %v\n", policy)
}
var jsonGroups []*ForgetGroup
for k, snapshotGroup := range snapshotGroups { for k, snapshotGroup := range snapshotGroups {
var key key var key key
@ -190,36 +195,50 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
return err return err
} }
var fg ForgetGroup
// Info // Info
Verbosef("snapshots") if !gopts.JSON {
Verbosef("snapshots")
}
var infoStrings []string var infoStrings []string
if GroupByTag { if GroupByTag {
infoStrings = append(infoStrings, "tags ["+strings.Join(key.Tags, ", ")+"]") infoStrings = append(infoStrings, "tags ["+strings.Join(key.Tags, ", ")+"]")
fg.Tags = key.Tags
} }
if GroupByHost { if GroupByHost {
infoStrings = append(infoStrings, "host ["+key.Hostname+"]") infoStrings = append(infoStrings, "host ["+key.Hostname+"]")
fg.Host = key.Hostname
} }
if GroupByPath { if GroupByPath {
infoStrings = append(infoStrings, "paths ["+strings.Join(key.Paths, ", ")+"]") infoStrings = append(infoStrings, "paths ["+strings.Join(key.Paths, ", ")+"]")
fg.Paths = key.Paths
} }
if infoStrings != nil { if infoStrings != nil && !gopts.JSON {
Verbosef(" for (" + strings.Join(infoStrings, ", ") + ")") Verbosef(" for (" + strings.Join(infoStrings, ", ") + ")")
} }
Verbosef(":\n\n") if !gopts.JSON {
Verbosef(":\n\n")
}
keep, remove, reasons := restic.ApplyPolicy(snapshotGroup, policy) keep, remove, reasons := restic.ApplyPolicy(snapshotGroup, policy)
if len(keep) != 0 && !gopts.Quiet { if len(keep) != 0 && !gopts.Quiet && !gopts.JSON {
Printf("keep %d snapshots:\n", len(keep)) Printf("keep %d snapshots:\n", len(keep))
PrintSnapshots(globalOptions.stdout, keep, reasons, opts.Compact) PrintSnapshots(globalOptions.stdout, keep, reasons, opts.Compact)
Printf("\n") Printf("\n")
} }
addJSONSnapshots(&fg.Keep, keep)
if len(remove) != 0 && !gopts.Quiet { if len(remove) != 0 && !gopts.Quiet && !gopts.JSON {
Printf("remove %d snapshots:\n", len(remove)) Printf("remove %d snapshots:\n", len(remove))
PrintSnapshots(globalOptions.stdout, remove, nil, opts.Compact) PrintSnapshots(globalOptions.stdout, remove, nil, opts.Compact)
Printf("\n") Printf("\n")
} }
addJSONSnapshots(&fg.Remove, remove)
fg.Reasons = reasons
jsonGroups = append(jsonGroups, &fg)
removeSnapshots += len(remove) removeSnapshots += len(remove)
@ -233,6 +252,13 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
} }
} }
} }
if gopts.JSON {
err = printJSONForget(gopts.stdout, jsonGroups)
if err != nil {
return err
}
}
} }
if removeSnapshots > 0 && opts.Prune { if removeSnapshots > 0 && opts.Prune {
@ -244,3 +270,28 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
return nil return nil
} }
// ForgetGroup helps to print what is forgotten in JSON.
type ForgetGroup struct {
Tags []string `json:"tags"`
Host string `json:"host"`
Paths []string `json:"paths"`
Keep []Snapshot `json:"keep"`
Remove []Snapshot `json:"remove"`
Reasons []restic.KeepReason `json:"reasons"`
}
func addJSONSnapshots(js *[]Snapshot, list restic.Snapshots) {
for _, sn := range list {
k := Snapshot{
Snapshot: sn,
ID: sn.ID(),
ShortID: sn.ID().Str(),
}
*js = append(*js, k)
}
}
func printJSONForget(stdout io.Writer, forgets []*ForgetGroup) error {
return json.NewEncoder(stdout).Encode(forgets)
}

View File

@ -219,6 +219,35 @@ func testRunForget(t testing.TB, gopts GlobalOptions, args ...string) {
rtest.OK(t, runForget(opts, gopts, args)) rtest.OK(t, runForget(opts, gopts, args))
} }
func testRunForgetJSON(t testing.TB, gopts GlobalOptions, args ...string) {
buf := bytes.NewBuffer(nil)
oldJSON := gopts.JSON
gopts.stdout = buf
gopts.JSON = true
defer func() {
gopts.stdout = os.Stdout
gopts.JSON = oldJSON
}()
opts := ForgetOptions{
DryRun: true,
Last: 1,
}
rtest.OK(t, runForget(opts, gopts, args))
var forgets []*ForgetGroup
rtest.OK(t, json.Unmarshal(buf.Bytes(), &forgets))
rtest.Assert(t, len(forgets) == 1,
"Expected 1 snapshot group, got %v", len(forgets))
rtest.Assert(t, len(forgets[0].Keep) == 1,
"Expected 1 snapshot to be kept, got %v", len(forgets[0].Keep))
rtest.Assert(t, len(forgets[0].Remove) == 2,
"Expected 2 snapshots to be removed, got %v", len(forgets[0].Remove))
return
}
func testRunPrune(t testing.TB, gopts GlobalOptions) { func testRunPrune(t testing.TB, gopts GlobalOptions) {
rtest.OK(t, runPrune(gopts)) rtest.OK(t, runPrune(gopts))
} }
@ -1051,6 +1080,7 @@ func TestPrune(t *testing.T) {
rtest.Assert(t, len(snapshotIDs) == 3, rtest.Assert(t, len(snapshotIDs) == 3,
"expected 3 snapshot, got %v", snapshotIDs) "expected 3 snapshot, got %v", snapshotIDs)
testRunForgetJSON(t, env.gopts)
testRunForget(t, env.gopts, firstSnapshot[0].String()) testRunForget(t, env.gopts, firstSnapshot[0].String())
testRunPrune(t, env.gopts) testRunPrune(t, env.gopts)
testRunCheck(t, env.gopts) testRunCheck(t, env.gopts)