mirror of
https://github.com/restic/restic.git
synced 2025-08-12 11:47:43 +00:00
Moves files
This commit is contained in:
2
internal/migrations/doc.go
Normal file
2
internal/migrations/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package migrations contains migrations that can be applied to a repository and/or backend.
|
||||
package migrations
|
21
internal/migrations/interface.go
Normal file
21
internal/migrations/interface.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"restic"
|
||||
)
|
||||
|
||||
// Migration implements a data migration.
|
||||
type Migration interface {
|
||||
// Check returns true if the migration can be applied to a repo.
|
||||
Check(context.Context, restic.Repository) (bool, error)
|
||||
|
||||
// Apply runs the migration.
|
||||
Apply(context.Context, restic.Repository) error
|
||||
|
||||
// Name returns a short name.
|
||||
Name() string
|
||||
|
||||
// Descr returns a description what the migration does.
|
||||
Desc() string
|
||||
}
|
8
internal/migrations/list.go
Normal file
8
internal/migrations/list.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package migrations
|
||||
|
||||
// All contains all migrations.
|
||||
var All []Migration
|
||||
|
||||
func register(m Migration) {
|
||||
All = append(All, m)
|
||||
}
|
118
internal/migrations/s3_layout.go
Normal file
118
internal/migrations/s3_layout.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"restic"
|
||||
"restic/backend"
|
||||
"restic/backend/s3"
|
||||
"restic/debug"
|
||||
"restic/errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(&S3Layout{})
|
||||
}
|
||||
|
||||
// S3Layout migrates a repository on an S3 backend from the "s3legacy" to the
|
||||
// "default" layout.
|
||||
type S3Layout struct{}
|
||||
|
||||
// Check tests whether the migration can be applied.
|
||||
func (m *S3Layout) Check(ctx context.Context, repo restic.Repository) (bool, error) {
|
||||
be, ok := repo.Backend().(*s3.Backend)
|
||||
if !ok {
|
||||
debug.Log("backend is not s3")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if be.Layout.Name() != "s3legacy" {
|
||||
debug.Log("layout is not s3legacy")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func retry(max int, fail func(err error), f func() error) error {
|
||||
var err error
|
||||
for i := 0; i < max; i++ {
|
||||
err = f()
|
||||
if err == nil {
|
||||
return err
|
||||
}
|
||||
if fail != nil {
|
||||
fail(err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// maxErrors for retrying renames on s3.
|
||||
const maxErrors = 20
|
||||
|
||||
func (m *S3Layout) moveFiles(ctx context.Context, be *s3.Backend, l backend.Layout, t restic.FileType) error {
|
||||
printErr := func(err error) {
|
||||
fmt.Fprintf(os.Stderr, "renaming file returned error: %v\n", err)
|
||||
}
|
||||
|
||||
for name := range be.List(ctx, t) {
|
||||
h := restic.Handle{Type: t, Name: name}
|
||||
debug.Log("move %v", h)
|
||||
|
||||
retry(maxErrors, printErr, func() error {
|
||||
return be.Rename(h, l)
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Apply runs the migration.
|
||||
func (m *S3Layout) Apply(ctx context.Context, repo restic.Repository) error {
|
||||
be, ok := repo.Backend().(*s3.Backend)
|
||||
if !ok {
|
||||
debug.Log("backend is not s3")
|
||||
return errors.New("backend is not s3")
|
||||
}
|
||||
|
||||
oldLayout := &backend.S3LegacyLayout{
|
||||
Path: be.Path(),
|
||||
Join: path.Join,
|
||||
}
|
||||
|
||||
newLayout := &backend.DefaultLayout{
|
||||
Path: be.Path(),
|
||||
Join: path.Join,
|
||||
}
|
||||
|
||||
be.Layout = oldLayout
|
||||
|
||||
for _, t := range []restic.FileType{
|
||||
restic.SnapshotFile,
|
||||
restic.DataFile,
|
||||
restic.KeyFile,
|
||||
restic.LockFile,
|
||||
} {
|
||||
err := m.moveFiles(ctx, be, newLayout, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
be.Layout = newLayout
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns the name for this migration.
|
||||
func (m *S3Layout) Name() string {
|
||||
return "s3_layout"
|
||||
}
|
||||
|
||||
// Desc returns a short description what the migration does.
|
||||
func (m *S3Layout) Desc() string {
|
||||
return "move files from 's3legacy' to the 'default' repository layout"
|
||||
}
|
Reference in New Issue
Block a user