diff --git a/cmd/restic/cmd_init.go b/cmd/restic/cmd_init.go index ef0cbcfe8..50d8810d8 100644 --- a/cmd/restic/cmd_init.go +++ b/cmd/restic/cmd_init.go @@ -9,7 +9,6 @@ import ( "github.com/restic/restic/internal/backend/location" "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/global" - "github.com/restic/restic/internal/repository" "github.com/restic/restic/internal/restic" "github.com/restic/restic/internal/ui" "github.com/restic/restic/internal/ui/progress" @@ -77,45 +76,16 @@ func runInit(ctx context.Context, opts InitOptions, gopts global.Options, args [ version = uint(v) } - if version < restic.MinRepoVersion || version > restic.MaxRepoVersion { - return errors.Fatalf("only repository versions between %v and %v are allowed", restic.MinRepoVersion, restic.MaxRepoVersion) - } - chunkerPolynomial, err := maybeReadChunkerPolynomial(ctx, opts, gopts, printer) if err != nil { return err } - gopts.Repo, err = global.ReadRepo(gopts) - if err != nil { - return err - } - - gopts.Password, err = global.ReadPasswordTwice(ctx, gopts, - "enter password for new repository: ", - "enter password again: ") - if err != nil { - return err - } - - be, err := global.Create(ctx, gopts.Repo, gopts, gopts.Extended, printer) - if err != nil { - return errors.Fatalf("create repository at %s failed: %v", location.StripPassword(gopts.Backends, gopts.Repo), err) - } - - s, err := repository.New(be, repository.Options{ - Compression: gopts.Compression, - PackSize: gopts.PackSize * 1024 * 1024, - }) + s, err := global.CreateRepository(ctx, gopts, version, chunkerPolynomial, printer) if err != nil { return errors.Fatalf("%s", err) } - err = s.Init(ctx, version, gopts.Password, chunkerPolynomial) - if err != nil { - return errors.Fatalf("create key in repository at %s failed: %v", location.StripPassword(gopts.Backends, gopts.Repo), err) - } - if !gopts.JSON { printer.P("created restic repository %v at %s", s.Config().ID[:10], location.StripPassword(gopts.Backends, gopts.Repo)) if opts.CopyChunkerParameters && chunkerPolynomial != nil { diff --git a/internal/global/global.go b/internal/global/global.go index 420ad6436..e5f172b59 100644 --- a/internal/global/global.go +++ b/internal/global/global.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/restic/chunker" "github.com/restic/restic/internal/backend" "github.com/restic/restic/internal/backend/cache" "github.com/restic/restic/internal/backend/limiter" @@ -253,7 +254,7 @@ func ReadPasswordTwice(ctx context.Context, gopts Options, prompt1, prompt2 stri return pw1, nil } -func ReadRepo(gopts Options) (string, error) { +func readRepo(gopts Options) (string, error) { if gopts.Repo == "" && gopts.RepositoryFile == "" { return "", errors.Fatal("Please specify repository location (-r or --repository-file)") } @@ -282,16 +283,30 @@ const maxKeys = 20 // OpenRepository reads the password and opens the repository. func OpenRepository(ctx context.Context, gopts Options, printer progress.Printer) (*repository.Repository, error) { - repo, err := ReadRepo(gopts) + repo, err := readRepo(gopts) if err != nil { return nil, err } - be, err := open(ctx, repo, gopts, gopts.Extended, printer) + be, err := innerOpenBackend(ctx, repo, gopts, gopts.Extended, false, printer) if err != nil { return nil, err } + // check if config is there + fi, err := be.Stat(ctx, backend.Handle{Type: restic.ConfigFile}) + if be.IsNotExist(err) { + //nolint:staticcheck // capitalized error string is intentional + return nil, fmt.Errorf("Fatal: %w: unable to open config file: %v\nIs there a repository at the following location?\n%v", ErrNoRepository, err, location.StripPassword(gopts.Backends, repo)) + } + if err != nil { + return nil, errors.Fatalf("unable to open config file: %v\nIs there a repository at the following location?\n%v", err, location.StripPassword(gopts.Backends, repo)) + } + + if fi.Size == 0 { + return nil, errors.New("config file has zero size, invalid repository?") + } + s, err := repository.New(be, repository.Options{ Compression: gopts.Compression, PackSize: gopts.PackSize * 1024 * 1024, @@ -403,7 +418,46 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro return cfg, nil } -func innerOpen(ctx context.Context, s string, gopts Options, opts options.Options, create bool, printer progress.Printer) (backend.Backend, error) { +// CreateRepository a repository with the given version and chunker polynomial. +func CreateRepository(ctx context.Context, gopts Options, version uint, chunkerPolynomial *chunker.Pol, printer progress.Printer) (*repository.Repository, error) { + if version < restic.MinRepoVersion || version > restic.MaxRepoVersion { + return nil, errors.Fatalf("only repository versions between %v and %v are allowed", restic.MinRepoVersion, restic.MaxRepoVersion) + } + + repo, err := readRepo(gopts) + if err != nil { + return nil, err + } + + gopts.Password, err = ReadPasswordTwice(ctx, gopts, + "enter password for new repository: ", + "enter password again: ") + if err != nil { + return nil, err + } + + be, err := innerOpenBackend(ctx, repo, gopts, gopts.Extended, true, printer) + if err != nil { + return nil, errors.Fatalf("create repository at %s failed: %v", location.StripPassword(gopts.Backends, repo), err) + } + + s, err := repository.New(be, repository.Options{ + Compression: gopts.Compression, + PackSize: gopts.PackSize * 1024 * 1024, + }) + if err != nil { + return nil, errors.Fatalf("%s", err) + } + + err = s.Init(ctx, version, gopts.Password, chunkerPolynomial) + if err != nil { + return nil, errors.Fatalf("create key in repository at %s failed: %v", location.StripPassword(gopts.Backends, repo), err) + } + + return s, nil +} + +func innerOpenBackend(ctx context.Context, s string, gopts Options, opts options.Options, create bool, printer progress.Printer) (backend.Backend, error) { debug.Log("parsing location %v", location.StripPassword(gopts.Backends, s)) loc, err := location.Parse(gopts.Backends, s) if err != nil { @@ -481,32 +535,3 @@ func innerOpen(ctx context.Context, s string, gopts Options, opts options.Option return be, nil } - -// Open the backend specified by a location config. -func open(ctx context.Context, s string, gopts Options, opts options.Options, printer progress.Printer) (backend.Backend, error) { - be, err := innerOpen(ctx, s, gopts, opts, false, printer) - if err != nil { - return nil, err - } - - // check if config is there - fi, err := be.Stat(ctx, backend.Handle{Type: restic.ConfigFile}) - if be.IsNotExist(err) { - //nolint:staticcheck // capitalized error string is intentional - return nil, fmt.Errorf("Fatal: %w: unable to open config file: %v\nIs there a repository at the following location?\n%v", ErrNoRepository, err, location.StripPassword(gopts.Backends, s)) - } - if err != nil { - return nil, errors.Fatalf("unable to open config file: %v\nIs there a repository at the following location?\n%v", err, location.StripPassword(gopts.Backends, s)) - } - - if fi.Size == 0 { - return nil, errors.New("config file has zero size, invalid repository?") - } - - return be, nil -} - -// Create the backend specified by URI. -func Create(ctx context.Context, s string, gopts Options, opts options.Options, printer progress.Printer) (backend.Backend, error) { - return innerOpen(ctx, s, gopts, opts, true, printer) -} diff --git a/internal/global/global_test.go b/internal/global/global_test.go index a15d1b6fd..2982d81c1 100644 --- a/internal/global/global_test.go +++ b/internal/global/global_test.go @@ -16,7 +16,7 @@ func TestReadRepo(t *testing.T) { // test --repo option var gopts Options gopts.Repo = tempDir - repo, err := ReadRepo(gopts) + repo, err := readRepo(gopts) rtest.OK(t, err) rtest.Equals(t, tempDir, repo) @@ -27,13 +27,13 @@ func TestReadRepo(t *testing.T) { var gopts2 Options gopts2.RepositoryFile = foo - repo, err = ReadRepo(gopts2) + repo, err = readRepo(gopts2) rtest.OK(t, err) rtest.Equals(t, tempDir, repo) var gopts3 Options gopts3.RepositoryFile = foo + "-invalid" - _, err = ReadRepo(gopts3) + _, err = readRepo(gopts3) if err == nil { t.Fatal("must not read repository path from invalid file path") }