forked from TrueCloudLab/restic
ea59896bd6
Fixes restic#719 If the option is passed, restic will wait the specified duration of time and retry locking the repo every 10 seconds (or more often if the total timeout is relatively small). - Play nice with json output - Reduce wait time in lock tests - Rework timeout last attempt - Reduce test wait time to 0.1s - Use exponential back off for the retry lock - Don't pass gopts to lockRepo functions - Use global variable for retry sleep setup - Exit retry lock on cancel - Better wording for flag help - Reorder debug statement - Refactor tests - Lower max sleep time to 1m - Test that we cancel/timeout in time - Use non blocking sleep function - Refactor into minDuration func Co-authored-by: Julian Brost <julian@0x4a42.net>
136 lines
3.1 KiB
Go
136 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/restic/restic/internal/migrations"
|
|
"github.com/restic/restic/internal/restic"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var cmdMigrate = &cobra.Command{
|
|
Use: "migrate [flags] [migration name] [...]",
|
|
Short: "Apply migrations",
|
|
Long: `
|
|
The "migrate" command checks which migrations can be applied for a repository
|
|
and prints a list with available migration names. If one or more migration
|
|
names are specified, these migrations are applied.
|
|
|
|
EXIT STATUS
|
|
===========
|
|
|
|
Exit status is 0 if the command was successful, and non-zero if there was any error.
|
|
`,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return runMigrate(cmd.Context(), migrateOptions, globalOptions, args)
|
|
},
|
|
}
|
|
|
|
// MigrateOptions bundles all options for the 'check' command.
|
|
type MigrateOptions struct {
|
|
Force bool
|
|
}
|
|
|
|
var migrateOptions MigrateOptions
|
|
|
|
func init() {
|
|
cmdRoot.AddCommand(cmdMigrate)
|
|
f := cmdMigrate.Flags()
|
|
f.BoolVarP(&migrateOptions.Force, "force", "f", false, `apply a migration a second time`)
|
|
}
|
|
|
|
func checkMigrations(ctx context.Context, repo restic.Repository) error {
|
|
Printf("available migrations:\n")
|
|
found := false
|
|
|
|
for _, m := range migrations.All {
|
|
ok, _, err := m.Check(ctx, repo)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if ok {
|
|
Printf(" %v\t%v\n", m.Name(), m.Desc())
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
Printf("no migrations found\n")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func applyMigrations(ctx context.Context, opts MigrateOptions, gopts GlobalOptions, repo restic.Repository, args []string) error {
|
|
var firsterr error
|
|
for _, name := range args {
|
|
for _, m := range migrations.All {
|
|
if m.Name() == name {
|
|
ok, reason, err := m.Check(ctx, repo)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !ok {
|
|
if !opts.Force {
|
|
if reason == "" {
|
|
reason = "check failed"
|
|
}
|
|
Warnf("migration %v cannot be applied: %v\nIf you want to apply this migration anyway, re-run with option --force\n", m.Name(), reason)
|
|
continue
|
|
}
|
|
|
|
Warnf("check for migration %v failed, continuing anyway\n", m.Name())
|
|
}
|
|
|
|
if m.RepoCheck() {
|
|
Printf("checking repository integrity...\n")
|
|
|
|
checkOptions := CheckOptions{}
|
|
checkGopts := gopts
|
|
// the repository is already locked
|
|
checkGopts.NoLock = true
|
|
err = runCheck(ctx, checkOptions, checkGopts, []string{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
Printf("applying migration %v...\n", m.Name())
|
|
if err = m.Apply(ctx, repo); err != nil {
|
|
Warnf("migration %v failed: %v\n", m.Name(), err)
|
|
if firsterr == nil {
|
|
firsterr = err
|
|
}
|
|
continue
|
|
}
|
|
|
|
Printf("migration %v: success\n", m.Name())
|
|
}
|
|
}
|
|
}
|
|
|
|
return firsterr
|
|
}
|
|
|
|
func runMigrate(ctx context.Context, opts MigrateOptions, gopts GlobalOptions, args []string) error {
|
|
repo, err := OpenRepository(ctx, gopts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
lock, ctx, err := lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
|
|
defer unlockRepo(lock)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(args) == 0 {
|
|
return checkMigrations(ctx, repo)
|
|
}
|
|
|
|
return applyMigrations(ctx, opts, gopts, repo, args)
|
|
}
|