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

rewrite: cleanup new metadata options and fix no parameters check

This commit is contained in:
Michael Eischer 2023-12-24 14:36:27 +01:00
parent 7de97d7480
commit 893d0d6325
2 changed files with 36 additions and 33 deletions

View File

@ -52,12 +52,16 @@ type snapshotMetadata struct {
Time *time.Time Time *time.Time
} }
type SnapshotMetadataArgs struct { type snapshotMetadataArgs struct {
Hostname string Hostname string
Time string Time string
} }
func (sma SnapshotMetadataArgs) convert() (*snapshotMetadata, error) { func (sma snapshotMetadataArgs) empty() bool {
return sma.Hostname == "" && sma.Time == ""
}
func (sma snapshotMetadataArgs) convert() (*snapshotMetadata, error) {
if sma.Time == "" && sma.Hostname == "" { if sma.Time == "" && sma.Hostname == "" {
return nil, nil return nil, nil
} }
@ -78,16 +82,15 @@ func (sma SnapshotMetadataArgs) convert() (*snapshotMetadata, error) {
// RewriteOptions collects all options for the rewrite command. // RewriteOptions collects all options for the rewrite command.
type RewriteOptions struct { type RewriteOptions struct {
Forget bool Forget bool
DryRun bool DryRun bool
Metadata *SnapshotMetadataArgs
metadata snapshotMetadataArgs
restic.SnapshotFilter restic.SnapshotFilter
excludePatternOptions excludePatternOptions
} }
var rewriteOptions RewriteOptions var rewriteOptions RewriteOptions
var metadataOptions SnapshotMetadataArgs
func init() { func init() {
cmdRoot.AddCommand(cmdRewrite) cmdRoot.AddCommand(cmdRewrite)
@ -95,15 +98,15 @@ func init() {
f := cmdRewrite.Flags() f := cmdRewrite.Flags()
f.BoolVarP(&rewriteOptions.Forget, "forget", "", false, "remove original snapshots after creating new ones") f.BoolVarP(&rewriteOptions.Forget, "forget", "", false, "remove original snapshots after creating new ones")
f.BoolVarP(&rewriteOptions.DryRun, "dry-run", "n", false, "do not do anything, just print what would be done") f.BoolVarP(&rewriteOptions.DryRun, "dry-run", "n", false, "do not do anything, just print what would be done")
f.StringVar(&metadataOptions.Hostname, "new-host", "", "rewrite hostname") f.StringVar(&rewriteOptions.metadata.Hostname, "new-host", "", "replace hostname")
f.StringVar(&metadataOptions.Time, "new-time", "", "rewrite time of the backup") f.StringVar(&rewriteOptions.metadata.Time, "new-time", "", "replace time of the backup")
rewriteOptions.Metadata = &metadataOptions
initMultiSnapshotFilter(f, &rewriteOptions.SnapshotFilter, true) initMultiSnapshotFilter(f, &rewriteOptions.SnapshotFilter, true)
initExcludePatternOptions(f, &rewriteOptions.excludePatternOptions) initExcludePatternOptions(f, &rewriteOptions.excludePatternOptions)
} }
type rewriteFilterFunc func(ctx context.Context, sn *restic.Snapshot) (restic.ID, error)
func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *restic.Snapshot, opts RewriteOptions) (bool, error) { func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *restic.Snapshot, opts RewriteOptions) (bool, error) {
if sn.Tree == nil { if sn.Tree == nil {
return false, errors.Errorf("snapshot %v has nil tree", sn.ID().Str()) return false, errors.Errorf("snapshot %v has nil tree", sn.ID().Str())
@ -114,7 +117,7 @@ func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *resti
return false, err return false, err
} }
metadata, err := opts.Metadata.convert() metadata, err := opts.metadata.convert()
if err != nil { if err != nil {
return false, err return false, err
@ -146,7 +149,8 @@ func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *resti
}, opts.DryRun, opts.Forget, metadata, "rewrite") }, opts.DryRun, opts.Forget, metadata, "rewrite")
} }
func filterAndReplaceSnapshot(ctx context.Context, repo restic.Repository, sn *restic.Snapshot, filter func(ctx context.Context, sn *restic.Snapshot) (restic.ID, error), dryRun bool, forget bool, metadata *snapshotMetadata, addTag string) (bool, error) { func filterAndReplaceSnapshot(ctx context.Context, repo restic.Repository, sn *restic.Snapshot,
filter rewriteFilterFunc, dryRun bool, forget bool, newMetadata *snapshotMetadata, addTag string) (bool, error) {
wg, wgCtx := errgroup.WithContext(ctx) wg, wgCtx := errgroup.WithContext(ctx)
repo.StartPackUploader(wgCtx, wg) repo.StartPackUploader(wgCtx, wg)
@ -180,7 +184,7 @@ func filterAndReplaceSnapshot(ctx context.Context, repo restic.Repository, sn *r
return true, nil return true, nil
} }
if filteredTree == *sn.Tree && metadata == nil { if filteredTree == *sn.Tree && newMetadata == nil {
debug.Log("Snapshot %v not modified", sn) debug.Log("Snapshot %v not modified", sn)
return false, nil return false, nil
} }
@ -193,12 +197,12 @@ func filterAndReplaceSnapshot(ctx context.Context, repo restic.Repository, sn *r
Verbosef("would remove old snapshot\n") Verbosef("would remove old snapshot\n")
} }
if metadata != nil && metadata.Time != nil { if newMetadata != nil && newMetadata.Time != nil {
Verbosef("would set time to %s\n", metadata.Time) Verbosef("would set time to %s\n", newMetadata.Time)
} }
if metadata != nil && metadata.Hostname != "" { if newMetadata != nil && newMetadata.Hostname != "" {
Verbosef("would set time to %s\n", metadata.Hostname) Verbosef("would set time to %s\n", newMetadata.Hostname)
} }
return true, nil return true, nil
@ -212,15 +216,14 @@ func filterAndReplaceSnapshot(ctx context.Context, repo restic.Repository, sn *r
sn.AddTags([]string{addTag}) sn.AddTags([]string{addTag})
} }
if metadata != nil && metadata.Time != nil { if newMetadata != nil && newMetadata.Time != nil {
Verbosef("Setting time to %s\n", *metadata.Time) Verbosef("setting time to %s\n", *newMetadata.Time)
sn.Time = *metadata.Time sn.Time = *newMetadata.Time
} }
if metadata != nil && metadata.Hostname != "" { if newMetadata != nil && newMetadata.Hostname != "" {
Verbosef("Setting host to %s\n", metadata.Hostname) Verbosef("setting host to %s\n", newMetadata.Hostname)
sn.Hostname = metadata.Hostname sn.Hostname = newMetadata.Hostname
} }
// Save the new snapshot. // Save the new snapshot.
@ -242,7 +245,7 @@ func filterAndReplaceSnapshot(ctx context.Context, repo restic.Repository, sn *r
} }
func runRewrite(ctx context.Context, opts RewriteOptions, gopts GlobalOptions, args []string) error { func runRewrite(ctx context.Context, opts RewriteOptions, gopts GlobalOptions, args []string) error {
if opts.excludePatternOptions.Empty() && opts.Metadata == nil { if opts.excludePatternOptions.Empty() && opts.metadata.empty() {
return errors.Fatal("Nothing to do: no excludes provided and no new metadata provided") return errors.Fatal("Nothing to do: no excludes provided and no new metadata provided")
} }

View File

@ -9,13 +9,13 @@ import (
rtest "github.com/restic/restic/internal/test" rtest "github.com/restic/restic/internal/test"
) )
func testRunRewriteExclude(t testing.TB, gopts GlobalOptions, excludes []string, forget bool, metadata *SnapshotMetadataArgs) { func testRunRewriteExclude(t testing.TB, gopts GlobalOptions, excludes []string, forget bool, metadata snapshotMetadataArgs) {
opts := RewriteOptions{ opts := RewriteOptions{
excludePatternOptions: excludePatternOptions{ excludePatternOptions: excludePatternOptions{
Excludes: excludes, Excludes: excludes,
}, },
Forget: forget, Forget: forget,
Metadata: metadata, metadata: metadata,
} }
rtest.OK(t, runRewrite(context.TODO(), opts, gopts, nil)) rtest.OK(t, runRewrite(context.TODO(), opts, gopts, nil))
@ -39,7 +39,7 @@ func TestRewrite(t *testing.T) {
createBasicRewriteRepo(t, env) createBasicRewriteRepo(t, env)
// exclude some data // exclude some data
testRunRewriteExclude(t, env.gopts, []string{"3"}, false, &SnapshotMetadataArgs{Hostname: "", Time: ""}) testRunRewriteExclude(t, env.gopts, []string{"3"}, false, snapshotMetadataArgs{Hostname: "", Time: ""})
snapshotIDs := testRunList(t, "snapshots", env.gopts) snapshotIDs := testRunList(t, "snapshots", env.gopts)
rtest.Assert(t, len(snapshotIDs) == 2, "expected two snapshots, got %v", snapshotIDs) rtest.Assert(t, len(snapshotIDs) == 2, "expected two snapshots, got %v", snapshotIDs)
testRunCheck(t, env.gopts) testRunCheck(t, env.gopts)
@ -51,7 +51,7 @@ func TestRewriteUnchanged(t *testing.T) {
snapshotID := createBasicRewriteRepo(t, env) snapshotID := createBasicRewriteRepo(t, env)
// use an exclude that will not exclude anything // use an exclude that will not exclude anything
testRunRewriteExclude(t, env.gopts, []string{"3dflkhjgdflhkjetrlkhjgfdlhkj"}, false, &SnapshotMetadataArgs{Hostname: "", Time: ""}) testRunRewriteExclude(t, env.gopts, []string{"3dflkhjgdflhkjetrlkhjgfdlhkj"}, false, snapshotMetadataArgs{Hostname: "", Time: ""})
newSnapshotIDs := testRunList(t, "snapshots", env.gopts) newSnapshotIDs := testRunList(t, "snapshots", env.gopts)
rtest.Assert(t, len(newSnapshotIDs) == 1, "expected one snapshot, got %v", newSnapshotIDs) rtest.Assert(t, len(newSnapshotIDs) == 1, "expected one snapshot, got %v", newSnapshotIDs)
rtest.Assert(t, snapshotID == newSnapshotIDs[0], "snapshot id changed unexpectedly") rtest.Assert(t, snapshotID == newSnapshotIDs[0], "snapshot id changed unexpectedly")
@ -64,7 +64,7 @@ func TestRewriteReplace(t *testing.T) {
snapshotID := createBasicRewriteRepo(t, env) snapshotID := createBasicRewriteRepo(t, env)
// exclude some data // exclude some data
testRunRewriteExclude(t, env.gopts, []string{"3"}, true, &SnapshotMetadataArgs{Hostname: "", Time: ""}) testRunRewriteExclude(t, env.gopts, []string{"3"}, true, snapshotMetadataArgs{Hostname: "", Time: ""})
newSnapshotIDs := testRunList(t, "snapshots", env.gopts) newSnapshotIDs := testRunList(t, "snapshots", env.gopts)
rtest.Assert(t, len(newSnapshotIDs) == 1, "expected one snapshot, got %v", newSnapshotIDs) rtest.Assert(t, len(newSnapshotIDs) == 1, "expected one snapshot, got %v", newSnapshotIDs)
rtest.Assert(t, snapshotID != newSnapshotIDs[0], "snapshot id should have changed") rtest.Assert(t, snapshotID != newSnapshotIDs[0], "snapshot id should have changed")
@ -73,14 +73,14 @@ func TestRewriteReplace(t *testing.T) {
testRunCheck(t, env.gopts) testRunCheck(t, env.gopts)
} }
func testRewriteMetadata(t *testing.T, metadata SnapshotMetadataArgs) { func testRewriteMetadata(t *testing.T, metadata snapshotMetadataArgs) {
env, cleanup := withTestEnvironment(t) env, cleanup := withTestEnvironment(t)
env.gopts.backendTestHook = nil env.gopts.backendTestHook = nil
defer cleanup() defer cleanup()
createBasicRewriteRepo(t, env) createBasicRewriteRepo(t, env)
repo, _ := OpenRepository(context.TODO(), env.gopts) repo, _ := OpenRepository(context.TODO(), env.gopts)
testRunRewriteExclude(t, env.gopts, []string{}, true, &metadata) testRunRewriteExclude(t, env.gopts, []string{}, true, metadata)
snapshots := FindFilteredSnapshots(context.TODO(), repo, repo, &restic.SnapshotFilter{}, []string{}) snapshots := FindFilteredSnapshots(context.TODO(), repo, repo, &restic.SnapshotFilter{}, []string{})
@ -99,7 +99,7 @@ func TestRewriteMetadata(t *testing.T) {
newHost := "new host" newHost := "new host"
newTime := "1999-01-01 11:11:11" newTime := "1999-01-01 11:11:11"
for _, metadata := range []SnapshotMetadataArgs{ for _, metadata := range []snapshotMetadataArgs{
{Hostname: "", Time: newTime}, {Hostname: "", Time: newTime},
{Hostname: newHost, Time: ""}, {Hostname: newHost, Time: ""},
{Hostname: newHost, Time: newTime}, {Hostname: newHost, Time: newTime},