commit
36eaa22ed0
13 changed files with 33 additions and 14 deletions
1
Makefile
1
Makefile
|
@ -10,3 +10,4 @@ clean:
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test ./cmd/... ./internal/...
|
go test ./cmd/... ./internal/...
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ type BackupOptions struct {
|
||||||
Tags []string
|
Tags []string
|
||||||
Hostname string
|
Hostname string
|
||||||
FilesFrom string
|
FilesFrom string
|
||||||
|
TimeStamp string
|
||||||
}
|
}
|
||||||
|
|
||||||
var backupOptions BackupOptions
|
var backupOptions BackupOptions
|
||||||
|
@ -84,6 +85,7 @@ func init() {
|
||||||
f.StringArrayVar(&backupOptions.Tags, "tag", nil, "add a `tag` for the new snapshot (can be specified multiple times)")
|
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.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.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 {
|
func newScanProgress(gopts GlobalOptions) *restic.Progress {
|
||||||
|
@ -441,7 +443,15 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, args []string) error {
|
||||||
Warnf("%s\rwarning for %s: %v\n", ClearLine(), dir, err)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,10 @@ given as the arguments.
|
||||||
\fB\-\-tag\fP=[]
|
\fB\-\-tag\fP=[]
|
||||||
add a \fB\fCtag\fR for the new snapshot (can be specified multiple times)
|
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
|
.SH OPTIONS INHERITED FROM PARENT COMMANDS
|
||||||
.PP
|
.PP
|
||||||
|
|
|
@ -69,6 +69,7 @@ command:
|
||||||
--stdin read backup from stdin
|
--stdin read backup from stdin
|
||||||
--stdin-filename string file name to use when reading 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)
|
--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:
|
Global Flags:
|
||||||
--json set output mode to JSON for commands that support it
|
--json set output mode to JSON for commands that support it
|
||||||
|
|
|
@ -28,7 +28,7 @@ func (r *Reader) Archive(ctx context.Context, name string, rd io.Reader, p *rest
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.Log("start archiving %s", name)
|
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 {
|
if err != nil {
|
||||||
return nil, restic.ID{}, err
|
return nil, restic.ID{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
// 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
|
// used to compare the files to the ones archived at the time this snapshot was
|
||||||
// taken.
|
// 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)
|
paths = unique(paths)
|
||||||
sort.Sort(baseNameSlice(paths))
|
sort.Sort(baseNameSlice(paths))
|
||||||
|
|
||||||
|
@ -666,7 +666,7 @@ func (arch *Archiver) Snapshot(ctx context.Context, p *restic.Progress, paths, t
|
||||||
defer p.Done()
|
defer p.Done()
|
||||||
|
|
||||||
// create new snapshot
|
// create new snapshot
|
||||||
sn, err := restic.NewSnapshot(paths, tags, hostname)
|
sn, err := restic.NewSnapshot(paths, tags, hostname, time)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, restic.ID{}, err
|
return nil, restic.ID{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ func archiveDirectory(b testing.TB) {
|
||||||
|
|
||||||
arch := archiver.New(repo)
|
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)
|
OK(b, err)
|
||||||
|
|
||||||
b.Logf("snapshot archived as %v", id)
|
b.Logf("snapshot archived as %v", id)
|
||||||
|
@ -302,7 +302,7 @@ func TestArchiveEmptySnapshot(t *testing.T) {
|
||||||
|
|
||||||
arch := archiver.New(repo)
|
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 {
|
if err == nil {
|
||||||
t.Errorf("expected error for empty snapshot, got nil")
|
t.Errorf("expected error for empty snapshot, got nil")
|
||||||
}
|
}
|
||||||
|
@ -354,7 +354,7 @@ func TestArchiveNameCollision(t *testing.T) {
|
||||||
|
|
||||||
arch := archiver.New(repo)
|
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)
|
OK(t, err)
|
||||||
|
|
||||||
t.Logf("snapshot archived as %v", id)
|
t.Logf("snapshot archived as %v", id)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package archiver
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
)
|
)
|
||||||
|
@ -10,7 +11,7 @@ import (
|
||||||
// TestSnapshot creates a new snapshot of path.
|
// TestSnapshot creates a new snapshot of path.
|
||||||
func TestSnapshot(t testing.TB, repo restic.Repository, path string, parent *restic.ID) *restic.Snapshot {
|
func TestSnapshot(t testing.TB, repo restic.Repository, path string, parent *restic.ID) *restic.Snapshot {
|
||||||
arch := New(repo)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/archiver"
|
"github.com/restic/restic/internal/archiver"
|
||||||
"github.com/restic/restic/internal/checker"
|
"github.com/restic/restic/internal/checker"
|
||||||
|
@ -305,7 +306,7 @@ func TestCheckerModifiedData(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
arch := archiver.New(repo)
|
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)
|
test.OK(t, err)
|
||||||
t.Logf("archived as %v", id.Str())
|
t.Logf("archived as %v", id.Str())
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ type Snapshot struct {
|
||||||
|
|
||||||
// NewSnapshot returns an initialized snapshot struct for the current user and
|
// NewSnapshot returns an initialized snapshot struct for the current user and
|
||||||
// time.
|
// 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 {
|
for i, path := range paths {
|
||||||
if p, err := filepath.Abs(path); err != nil {
|
if p, err := filepath.Abs(path); err != nil {
|
||||||
paths[i] = p
|
paths[i] = p
|
||||||
|
@ -38,7 +38,7 @@ func NewSnapshot(paths []string, tags []string, hostname string) (*Snapshot, err
|
||||||
|
|
||||||
sn := &Snapshot{
|
sn := &Snapshot{
|
||||||
Paths: paths,
|
Paths: paths,
|
||||||
Time: time.Now(),
|
Time: time,
|
||||||
Tags: tags,
|
Tags: tags,
|
||||||
Hostname: hostname,
|
Hostname: hostname,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package restic_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
. "github.com/restic/restic/internal/test"
|
. "github.com/restic/restic/internal/test"
|
||||||
|
@ -10,6 +11,6 @@ import (
|
||||||
func TestNewSnapshot(t *testing.T) {
|
func TestNewSnapshot(t *testing.T) {
|
||||||
paths := []string{"/home/foobar"}
|
paths := []string{"/home/foobar"}
|
||||||
|
|
||||||
_, err := restic.NewSnapshot(paths, nil, "foo")
|
_, err := restic.NewSnapshot(paths, nil, "foo", time.Now())
|
||||||
OK(t, err)
|
OK(t, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
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"))
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TestWalkTree(t *testing.T) {
|
||||||
|
|
||||||
// archive a few files
|
// archive a few files
|
||||||
arch := archiver.New(repo)
|
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)
|
OK(t, err)
|
||||||
|
|
||||||
// flush repo, write all packs
|
// flush repo, write all packs
|
||||||
|
|
Loading…
Reference in a new issue