From 43ff971dfd94ee31b62a936d6101404d8128a315 Mon Sep 17 00:00:00 2001 From: Tobias Klein Date: Tue, 29 Aug 2017 18:29:46 +0200 Subject: [PATCH 1/5] new sub-option for backup: time New option to specify the timestamp for a backup --- cmd/restic/cmd_backup.go | 12 +++++++++++- internal/archiver/archive_reader.go | 2 +- internal/archiver/archiver.go | 4 ++-- internal/archiver/testing.go | 3 ++- internal/restic/snapshot.go | 4 ++-- internal/restic/testing.go | 2 +- 6 files changed, 19 insertions(+), 8 deletions(-) diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index 09a4ba2f5..d0150da24 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -66,6 +66,7 @@ type BackupOptions struct { Tags []string Hostname string FilesFrom string + TimeStamp string } var backupOptions BackupOptions @@ -86,6 +87,7 @@ func init() { f.StringArrayVar(&backupOptions.Tags, "tag", nil, "add a `tag` for the new snapshot (can be specified multiple times)") f.StringVar(&backupOptions.Hostname, "hostname", "", "set the `hostname` for the snapshot manually") f.StringVar(&backupOptions.FilesFrom, "files-from", "", "read the files to backup from file (can be combined with file args)") + f.StringVar(&backupOptions.TimeStamp, "time", "", "time of the backup (ex. '2012-11-01 22:08:41') (default: now)") } func newScanProgress(gopts GlobalOptions) *restic.Progress { @@ -493,7 +495,15 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, args []string) error { Warnf("%s\rwarning for %s: %v\n", ClearLine(), dir, err) } - _, id, err := arch.Snapshot(context.TODO(), newArchiveProgress(gopts, stat), target, opts.Tags, opts.Hostname, parentSnapshotID) + timeStamp := time.Now() + if opts.TimeStamp != "" { + timeStamp, err = time.Parse(TimeFormat, opts.TimeStamp) + if err != nil { + return errors.Fatalf("error in time option: %v\n", err) + } + } + + _, id, err := arch.Snapshot(context.TODO(), newArchiveProgress(gopts, stat), target, opts.Tags, opts.Hostname, parentSnapshotID, timeStamp) if err != nil { return err } diff --git a/internal/archiver/archive_reader.go b/internal/archiver/archive_reader.go index eaf422aab..b6dab993b 100644 --- a/internal/archiver/archive_reader.go +++ b/internal/archiver/archive_reader.go @@ -28,7 +28,7 @@ func (r *Reader) Archive(ctx context.Context, name string, rd io.Reader, p *rest } debug.Log("start archiving %s", name) - sn, err := restic.NewSnapshot([]string{name}, r.Tags, r.Hostname) + sn, err := restic.NewSnapshot([]string{name}, r.Tags, r.Hostname, time.Now()) if err != nil { return nil, restic.ID{}, err } diff --git a/internal/archiver/archiver.go b/internal/archiver/archiver.go index 3117ec509..9e7ee307d 100644 --- a/internal/archiver/archiver.go +++ b/internal/archiver/archiver.go @@ -651,7 +651,7 @@ func (p baseNameSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } // Snapshot creates a snapshot of the given paths. If parentrestic.ID is set, this is // used to compare the files to the ones archived at the time this snapshot was // taken. -func (arch *Archiver) Snapshot(ctx context.Context, p *restic.Progress, paths, tags []string, hostname string, parentID *restic.ID) (*restic.Snapshot, restic.ID, error) { +func (arch *Archiver) Snapshot(ctx context.Context, p *restic.Progress, paths, tags []string, hostname string, parentID *restic.ID, time time.Time) (*restic.Snapshot, restic.ID, error) { paths = unique(paths) sort.Sort(baseNameSlice(paths)) @@ -666,7 +666,7 @@ func (arch *Archiver) Snapshot(ctx context.Context, p *restic.Progress, paths, t defer p.Done() // create new snapshot - sn, err := restic.NewSnapshot(paths, tags, hostname) + sn, err := restic.NewSnapshot(paths, tags, hostname, time) if err != nil { return nil, restic.ID{}, err } diff --git a/internal/archiver/testing.go b/internal/archiver/testing.go index 37abea83f..d700135b4 100644 --- a/internal/archiver/testing.go +++ b/internal/archiver/testing.go @@ -3,6 +3,7 @@ package archiver import ( "context" "testing" + "time" "github.com/restic/restic/internal/restic" ) @@ -10,7 +11,7 @@ import ( // TestSnapshot creates a new snapshot of path. func TestSnapshot(t testing.TB, repo restic.Repository, path string, parent *restic.ID) *restic.Snapshot { arch := New(repo) - sn, _, err := arch.Snapshot(context.TODO(), nil, []string{path}, []string{"test"}, "localhost", parent) + sn, _, err := arch.Snapshot(context.TODO(), nil, []string{path}, []string{"test"}, "localhost", parent, time.Now()) if err != nil { t.Fatal(err) } diff --git a/internal/restic/snapshot.go b/internal/restic/snapshot.go index c6e0dad50..f73be6937 100644 --- a/internal/restic/snapshot.go +++ b/internal/restic/snapshot.go @@ -29,7 +29,7 @@ type Snapshot struct { // NewSnapshot returns an initialized snapshot struct for the current user and // time. -func NewSnapshot(paths []string, tags []string, hostname string) (*Snapshot, error) { +func NewSnapshot(paths []string, tags []string, hostname string, time time.Time) (*Snapshot, error) { for i, path := range paths { if p, err := filepath.Abs(path); err != nil { paths[i] = p @@ -38,7 +38,7 @@ func NewSnapshot(paths []string, tags []string, hostname string) (*Snapshot, err sn := &Snapshot{ Paths: paths, - Time: time.Now(), + Time: time, Tags: tags, Hostname: hostname, } diff --git a/internal/restic/testing.go b/internal/restic/testing.go index 7ddba731a..5e1f3372b 100644 --- a/internal/restic/testing.go +++ b/internal/restic/testing.go @@ -164,7 +164,7 @@ func TestCreateSnapshot(t testing.TB, repo Repository, at time.Time, depth int, t.Logf("create fake snapshot at %s with seed %d", at, seed) fakedir := fmt.Sprintf("fakedir-at-%v", at.Format("2006-01-02 15:04:05")) - snapshot, err := NewSnapshot([]string{fakedir}, []string{"test"}, "foo") + snapshot, err := NewSnapshot([]string{fakedir}, []string{"test"}, "foo", time.Now()) if err != nil { t.Fatal(err) } From 087c3fe1dc5144ff1a1ba8bb79230ff66497d2f8 Mon Sep 17 00:00:00 2001 From: Tobias Klein Date: Sat, 2 Sep 2017 19:28:09 +0200 Subject: [PATCH 2/5] tests updated --- internal/archiver/archiver_test.go | 4 ++-- internal/checker/checker_test.go | 3 ++- internal/restic/snapshot_test.go | 3 ++- internal/walk/walk_test.go | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/internal/archiver/archiver_test.go b/internal/archiver/archiver_test.go index aaaf02a22..88c85aa98 100644 --- a/internal/archiver/archiver_test.go +++ b/internal/archiver/archiver_test.go @@ -108,7 +108,7 @@ func archiveDirectory(b testing.TB) { arch := archiver.New(repo) - _, id, err := arch.Snapshot(context.TODO(), nil, []string{BenchArchiveDirectory}, nil, "localhost", nil) + _, id, err := arch.Snapshot(context.TODO(), nil, []string{BenchArchiveDirectory}, nil, "localhost", nil, time.Now()) OK(b, err) b.Logf("snapshot archived as %v", id) @@ -302,7 +302,7 @@ func TestArchiveEmptySnapshot(t *testing.T) { arch := archiver.New(repo) - sn, id, err := arch.Snapshot(context.TODO(), nil, []string{"file-does-not-exist-123123213123", "file2-does-not-exist-too-123123123"}, nil, "localhost", nil) + sn, id, err := arch.Snapshot(context.TODO(), nil, []string{"file-does-not-exist-123123213123", "file2-does-not-exist-too-123123123"}, nil, "localhost", nil, time.Now()) if err == nil { t.Errorf("expected error for empty snapshot, got nil") } diff --git a/internal/checker/checker_test.go b/internal/checker/checker_test.go index 20be752be..d91c95054 100644 --- a/internal/checker/checker_test.go +++ b/internal/checker/checker_test.go @@ -7,6 +7,7 @@ import ( "path/filepath" "sort" "testing" + "time" "github.com/restic/restic/internal/archiver" "github.com/restic/restic/internal/checker" @@ -305,7 +306,7 @@ func TestCheckerModifiedData(t *testing.T) { defer cleanup() arch := archiver.New(repo) - _, id, err := arch.Snapshot(context.TODO(), nil, []string{"."}, nil, "localhost", nil) + _, id, err := arch.Snapshot(context.TODO(), nil, []string{"."}, nil, "localhost", nil, time.Now()) test.OK(t, err) t.Logf("archived as %v", id.Str()) diff --git a/internal/restic/snapshot_test.go b/internal/restic/snapshot_test.go index 50ebe7297..c02970ebb 100644 --- a/internal/restic/snapshot_test.go +++ b/internal/restic/snapshot_test.go @@ -2,6 +2,7 @@ package restic_test import ( "testing" + "time" "github.com/restic/restic/internal/restic" . "github.com/restic/restic/internal/test" @@ -10,6 +11,6 @@ import ( func TestNewSnapshot(t *testing.T) { paths := []string{"/home/foobar"} - _, err := restic.NewSnapshot(paths, nil, "foo") + _, err := restic.NewSnapshot(paths, nil, "foo", time.Now()) OK(t, err) } diff --git a/internal/walk/walk_test.go b/internal/walk/walk_test.go index 801e0aa32..699000292 100644 --- a/internal/walk/walk_test.go +++ b/internal/walk/walk_test.go @@ -25,7 +25,7 @@ func TestWalkTree(t *testing.T) { // archive a few files arch := archiver.New(repo) - sn, _, err := arch.Snapshot(context.TODO(), nil, dirs, nil, "localhost", nil) + sn, _, err := arch.Snapshot(context.TODO(), nil, dirs, nil, "localhost", nil, time.Now()) OK(t, err) // flush repo, write all packs From 81d7ecba2b105f5c55bad887ec4c77febbaf450a Mon Sep 17 00:00:00 2001 From: Tobias Klein Date: Sat, 9 Sep 2017 12:10:38 +0200 Subject: [PATCH 3/5] manual updated --- doc/man/restic-backup.1 | 4 ++++ doc/manual.rst | 1 + 2 files changed, 5 insertions(+) diff --git a/doc/man/restic-backup.1 b/doc/man/restic-backup.1 index 93e76ca19..60de16008 100644 --- a/doc/man/restic-backup.1 +++ b/doc/man/restic-backup.1 @@ -72,6 +72,10 @@ given as the arguments. \fB\-\-tag\fP=[] add a \fB\fCtag\fR for the new snapshot (can be specified multiple times) +.PP +\fB\-\-time\fP="" + time of the backup (ex. '2012\-11\-01 22:08:41') (default: now) + .SH OPTIONS INHERITED FROM PARENT COMMANDS .PP diff --git a/doc/manual.rst b/doc/manual.rst index 079457f13..cea9dcb1e 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -69,6 +69,7 @@ command: --stdin read backup from stdin --stdin-filename string file name to use when reading from stdin --tag tag add a tag for the new snapshot (can be specified multiple times) + --time string time of the backup (ex. '2012-11-01 22:08:41') (default: now) Global Flags: --json set output mode to JSON for commands that support it From f26c0cb70fe3796630adfa69021b70a3fbe3b6be Mon Sep 17 00:00:00 2001 From: Tobias Klein Date: Sat, 9 Sep 2017 14:58:07 +0200 Subject: [PATCH 4/5] testcase updated --- internal/archiver/archiver_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/archiver/archiver_test.go b/internal/archiver/archiver_test.go index 88c85aa98..cc29ae330 100644 --- a/internal/archiver/archiver_test.go +++ b/internal/archiver/archiver_test.go @@ -354,7 +354,7 @@ func TestArchiveNameCollision(t *testing.T) { arch := archiver.New(repo) - sn, id, err := arch.Snapshot(context.TODO(), nil, []string{"testfile", filepath.Join("..", "testfile")}, nil, "localhost", nil) + sn, id, err := arch.Snapshot(context.TODO(), nil, []string{"testfile", filepath.Join("..", "testfile")}, nil, "localhost", nil, time.Now()) OK(t, err) t.Logf("snapshot archived as %v", id) From bee09c1a0f595f93b746cea6036e28d5a852da49 Mon Sep 17 00:00:00 2001 From: Tobias Klein Date: Sat, 9 Sep 2017 16:33:51 +0200 Subject: [PATCH 5/5] test --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 840714a48..7e07ec8a0 100644 --- a/Makefile +++ b/Makefile @@ -10,3 +10,4 @@ clean: test: go test ./cmd/... ./internal/... +