OneDrive CLI commands (#739)
## Description Wires up the OneDrive Backup(create,list,details,delete) and Restore commands Unit tests added but integration tests will be added after the underlying operation PRs are merged. ## Type of change Please check the type of change your PR introduces: - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 🐹 Trivial/Minor ## Issue(s) #658 #668 ## Test Plan <!-- How will this be tested prior to merging.--> - [x] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
31e4a68355
commit
a9b0e2e7ee
@ -13,6 +13,7 @@ var subCommands = []*cobra.Command{
|
|||||||
|
|
||||||
var serviceCommands = []func(parent *cobra.Command) *cobra.Command{
|
var serviceCommands = []func(parent *cobra.Command) *cobra.Command{
|
||||||
addExchangeCommands,
|
addExchangeCommands,
|
||||||
|
addOneDriveCommands,
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCommands attaches all `corso backup * *` commands to the parent.
|
// AddCommands attaches all `corso backup * *` commands to the parent.
|
||||||
|
|||||||
252
src/cli/backup/onedrive.go
Normal file
252
src/cli/backup/onedrive.go
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
package backup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cli/config"
|
||||||
|
"github.com/alcionai/corso/src/cli/options"
|
||||||
|
. "github.com/alcionai/corso/src/cli/print"
|
||||||
|
"github.com/alcionai/corso/src/cli/utils"
|
||||||
|
"github.com/alcionai/corso/src/internal/model"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup"
|
||||||
|
"github.com/alcionai/corso/src/pkg/repository"
|
||||||
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// setup and globals
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const oneDriveServiceCommand = "onedrive"
|
||||||
|
|
||||||
|
// called by backup.go to map parent subcommands to provider-specific handling.
|
||||||
|
func addOneDriveCommands(parent *cobra.Command) *cobra.Command {
|
||||||
|
var (
|
||||||
|
c *cobra.Command
|
||||||
|
fs *pflag.FlagSet
|
||||||
|
)
|
||||||
|
|
||||||
|
switch parent.Use {
|
||||||
|
case createCommand:
|
||||||
|
c, fs = utils.AddCommand(parent, oneDriveCreateCmd())
|
||||||
|
|
||||||
|
fs.StringArrayVar(&user, "user", nil,
|
||||||
|
"Backup OneDrive data by user ID; accepts "+utils.Wildcard+" to select all users")
|
||||||
|
options.AddOperationFlags(c)
|
||||||
|
|
||||||
|
case listCommand:
|
||||||
|
c, _ = utils.AddCommand(parent, oneDriveListCmd())
|
||||||
|
|
||||||
|
case detailsCommand:
|
||||||
|
c, fs = utils.AddCommand(parent, oneDriveDetailsCmd())
|
||||||
|
fs.StringVar(&backupID, "backup", "", "ID of the backup containing the details to be shown")
|
||||||
|
cobra.CheckErr(c.MarkFlagRequired("backup"))
|
||||||
|
|
||||||
|
case deleteCommand:
|
||||||
|
c, fs = utils.AddCommand(parent, oneDriveDeleteCmd())
|
||||||
|
fs.StringVar(&backupID, "backup", "", "ID of the backup containing the details to be shown")
|
||||||
|
cobra.CheckErr(c.MarkFlagRequired("backup"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// backup create
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// `corso backup create onedrive [<flag>...]`
|
||||||
|
func oneDriveCreateCmd() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: oneDriveServiceCommand,
|
||||||
|
Short: "Backup M365 OneDrive service data",
|
||||||
|
RunE: createOneDriveCmd,
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// processes an onedrive service backup.
|
||||||
|
func createOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validateOneDriveBackupCreateFlags(user); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, acct, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := repository.Connect(ctx, acct, s, options.Control())
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||||
|
}
|
||||||
|
|
||||||
|
defer utils.CloseRepo(ctx, r)
|
||||||
|
|
||||||
|
sel := oneDriveBackupCreateSelectors(user)
|
||||||
|
|
||||||
|
bo, err := r.NewBackup(ctx, sel)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrap(err, "Failed to initialize OneDrive backup"))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bo.Run(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrap(err, "Failed to run OneDrive backup"))
|
||||||
|
}
|
||||||
|
|
||||||
|
bu, err := r.Backup(ctx, bo.Results.BackupID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Unable to retrieve backup results from storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
bu.Print(ctx)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateOneDriveBackupCreateFlags(users []string) error {
|
||||||
|
if len(users) == 0 {
|
||||||
|
return errors.New("requires one or more --user ids or the wildcard --user *")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func oneDriveBackupCreateSelectors(users []string) selectors.Selector {
|
||||||
|
sel := selectors.NewOneDriveBackup()
|
||||||
|
sel.Include(sel.Users(users))
|
||||||
|
|
||||||
|
return sel.Selector
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// backup list
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// `corso backup list onedrive [<flag>...]`
|
||||||
|
func oneDriveListCmd() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: oneDriveServiceCommand,
|
||||||
|
Short: "List the history of M365 OneDrive service backups",
|
||||||
|
RunE: listOneDriveCmd,
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lists the history of backup operations
|
||||||
|
func listOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
s, acct, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := repository.Connect(ctx, acct, s, options.Control())
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||||
|
}
|
||||||
|
|
||||||
|
defer utils.CloseRepo(ctx, r)
|
||||||
|
|
||||||
|
bs, err := r.Backups(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrap(err, "Failed to list backups in the repository"))
|
||||||
|
}
|
||||||
|
|
||||||
|
backup.PrintAll(ctx, bs)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// backup details
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// `corso backup details onedrive [<flag>...]`
|
||||||
|
func oneDriveDetailsCmd() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: oneDriveServiceCommand,
|
||||||
|
Short: "Shows the details of a M365 OneDrive service backup",
|
||||||
|
RunE: detailsOneDriveCmd,
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lists the history of backup operations
|
||||||
|
func detailsOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s, acct, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := repository.Connect(ctx, acct, s, options.Control())
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||||
|
}
|
||||||
|
|
||||||
|
defer utils.CloseRepo(ctx, r)
|
||||||
|
|
||||||
|
ds, _, err := r.BackupDetails(ctx, backupID)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrap(err, "Failed to get backup details in the repository"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Support selectors and filters
|
||||||
|
|
||||||
|
ds.PrintEntries(ctx)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// `corso backup delete onedrive [<flag>...]`
|
||||||
|
func oneDriveDeleteCmd() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: oneDriveServiceCommand,
|
||||||
|
Short: "Delete backed-up M365 OneDrive service data",
|
||||||
|
RunE: deleteOneDriveCmd,
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// deletes an exchange service backup.
|
||||||
|
func deleteOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s, acct, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := repository.Connect(ctx, acct, s, options.Control())
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||||
|
}
|
||||||
|
|
||||||
|
defer utils.CloseRepo(ctx, r)
|
||||||
|
|
||||||
|
if err := r.DeleteBackup(ctx, model.StableID(backupID)); err != nil {
|
||||||
|
return Only(ctx, errors.Wrapf(err, "Deleting backup %s", backupID))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
76
src/cli/backup/onedrive_test.go
Normal file
76
src/cli/backup/onedrive_test.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package backup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OneDriveSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOneDriveSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(OneDriveSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *OneDriveSuite) TestAddOneDriveCommands() {
|
||||||
|
expectUse := oneDriveServiceCommand
|
||||||
|
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
use string
|
||||||
|
expectUse string
|
||||||
|
expectShort string
|
||||||
|
expectRunE func(*cobra.Command, []string) error
|
||||||
|
}{
|
||||||
|
{"create onedrive", createCommand, expectUse, oneDriveCreateCmd().Short, createOneDriveCmd},
|
||||||
|
{"list onedrive", listCommand, expectUse, oneDriveListCmd().Short, listOneDriveCmd},
|
||||||
|
{"details onedrive", detailsCommand, expectUse, oneDriveDetailsCmd().Short, detailsOneDriveCmd},
|
||||||
|
{"delete onedrive", deleteCommand, expectUse, oneDriveDeleteCmd().Short, deleteOneDriveCmd},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
cmd := &cobra.Command{Use: test.use}
|
||||||
|
|
||||||
|
c := addOneDriveCommands(cmd)
|
||||||
|
require.NotNil(t, c)
|
||||||
|
|
||||||
|
cmds := cmd.Commands()
|
||||||
|
require.Len(t, cmds, 1)
|
||||||
|
|
||||||
|
child := cmds[0]
|
||||||
|
assert.Equal(t, test.expectUse, child.Use)
|
||||||
|
assert.Equal(t, test.expectShort, child.Short)
|
||||||
|
tester.AreSameFunc(t, test.expectRunE, child.RunE)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *OneDriveSuite) TestValidateOneDriveBackupCreateFlags() {
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
user []string
|
||||||
|
expect assert.ErrorAssertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no users",
|
||||||
|
expect: assert.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "users",
|
||||||
|
user: []string{"fnord"},
|
||||||
|
expect: assert.NoError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
test.expect(t, validateOneDriveBackupCreateFlags(test.user))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
98
src/cli/restore/onedrive.go
Normal file
98
src/cli/restore/onedrive.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package restore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cli/config"
|
||||||
|
"github.com/alcionai/corso/src/cli/options"
|
||||||
|
. "github.com/alcionai/corso/src/cli/print"
|
||||||
|
"github.com/alcionai/corso/src/cli/utils"
|
||||||
|
"github.com/alcionai/corso/src/pkg/repository"
|
||||||
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// called by restore.go to map parent subcommands to provider-specific handling.
|
||||||
|
func addOneDriveCommands(parent *cobra.Command) *cobra.Command {
|
||||||
|
var (
|
||||||
|
c *cobra.Command
|
||||||
|
fs *pflag.FlagSet
|
||||||
|
)
|
||||||
|
|
||||||
|
switch parent.Use {
|
||||||
|
case restoreCommand:
|
||||||
|
c, fs = utils.AddCommand(parent, oneDriveRestoreCmd())
|
||||||
|
fs.StringVar(&backupID, "backup", "", "ID of the backup to restore")
|
||||||
|
cobra.CheckErr(c.MarkFlagRequired("backup"))
|
||||||
|
|
||||||
|
fs.StringSliceVar(&user,
|
||||||
|
"user", nil,
|
||||||
|
"Restore all data by user ID; accepts "+utils.Wildcard+" to select all users")
|
||||||
|
|
||||||
|
// others
|
||||||
|
options.AddOperationFlags(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
const oneDriveServiceCommand = "onedrive"
|
||||||
|
|
||||||
|
// `corso restore onedrive [<flag>...]`
|
||||||
|
func oneDriveRestoreCmd() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: oneDriveServiceCommand,
|
||||||
|
Short: "Restore M365 OneDrive service data",
|
||||||
|
RunE: restoreOneDriveCmd,
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// processes an onedrive service restore.
|
||||||
|
func restoreOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := utils.ValidateOneDriveRestoreFlags(backupID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, a, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := repository.Connect(ctx, a, s, options.Control())
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||||
|
}
|
||||||
|
|
||||||
|
defer utils.CloseRepo(ctx, r)
|
||||||
|
|
||||||
|
sel := selectors.NewOneDriveRestore()
|
||||||
|
if user != nil {
|
||||||
|
sel.Include(sel.Users(user))
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no selector flags were specified, get all data in the service.
|
||||||
|
if len(sel.Scopes()) == 0 {
|
||||||
|
sel.Include(sel.Users(selectors.Any()))
|
||||||
|
}
|
||||||
|
|
||||||
|
ro, err := r.NewRestore(ctx, backupID, sel.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, errors.Wrap(err, "Failed to initialize OneDrive restore"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ro.Run(ctx); err != nil {
|
||||||
|
return Only(ctx, errors.Wrap(err, "Failed to run OneDrive restore"))
|
||||||
|
}
|
||||||
|
|
||||||
|
Infof(ctx, "Restored OneDrive in %s for user %s.\n", s.Provider, sel.ToPrintable().Resources())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
50
src/cli/restore/onedrive_test.go
Normal file
50
src/cli/restore/onedrive_test.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package restore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OneDriveSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOneDriveSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(OneDriveSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *OneDriveSuite) TestAddOneDriveCommands() {
|
||||||
|
expectUse := oneDriveServiceCommand
|
||||||
|
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
use string
|
||||||
|
expectUse string
|
||||||
|
expectShort string
|
||||||
|
expectRunE func(*cobra.Command, []string) error
|
||||||
|
}{
|
||||||
|
{"restore onedrive", restoreCommand, expectUse, oneDriveRestoreCmd().Short, restoreOneDriveCmd},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
cmd := &cobra.Command{Use: test.use}
|
||||||
|
|
||||||
|
c := addOneDriveCommands(cmd)
|
||||||
|
require.NotNil(t, c)
|
||||||
|
|
||||||
|
cmds := cmd.Commands()
|
||||||
|
require.Len(t, cmds, 1)
|
||||||
|
|
||||||
|
child := cmds[0]
|
||||||
|
assert.Equal(t, test.expectUse, child.Use)
|
||||||
|
assert.Equal(t, test.expectShort, child.Short)
|
||||||
|
tester.AreSameFunc(t, test.expectRunE, child.RunE)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
var restoreCommands = []func(parent *cobra.Command) *cobra.Command{
|
var restoreCommands = []func(parent *cobra.Command) *cobra.Command{
|
||||||
addExchangeCommands,
|
addExchangeCommands,
|
||||||
|
addOneDriveCommands,
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCommands attaches all `corso restore * *` commands to the parent.
|
// AddCommands attaches all `corso restore * *` commands to the parent.
|
||||||
|
|||||||
14
src/cli/utils/onedrive.go
Normal file
14
src/cli/utils/onedrive.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateOneDriveRestoreFlags checks common flags for correctness and interdependencies
|
||||||
|
func ValidateOneDriveRestoreFlags(backupID string) error {
|
||||||
|
if len(backupID) == 0 {
|
||||||
|
return errors.New("a backup ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/path"
|
"github.com/alcionai/corso/src/internal/path"
|
||||||
"github.com/alcionai/corso/src/internal/stats"
|
"github.com/alcionai/corso/src/internal/stats"
|
||||||
"github.com/alcionai/corso/src/pkg/account"
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
"github.com/alcionai/corso/src/pkg/logger"
|
"github.com/alcionai/corso/src/pkg/logger"
|
||||||
"github.com/alcionai/corso/src/pkg/selectors"
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
@ -118,16 +119,27 @@ func (op *RestoreOperation) Run(ctx context.Context) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
er, err := op.Selectors.ToExchangeRestore()
|
var fds *details.Details
|
||||||
if err != nil {
|
|
||||||
opStats.readErr = err
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// format the details and retrieve the items from kopia
|
switch op.Selectors.Service {
|
||||||
fds := er.Reduce(ctx, d)
|
case selectors.ServiceExchange:
|
||||||
if len(fds.Entries) == 0 {
|
er, err := op.Selectors.ToExchangeRestore()
|
||||||
return errors.New("nothing to restore: no items in the backup match the provided selectors")
|
if err != nil {
|
||||||
|
opStats.readErr = err
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// format the details and retrieve the items from kopia
|
||||||
|
fds = er.Reduce(ctx, d)
|
||||||
|
if len(fds.Entries) == 0 {
|
||||||
|
return errors.New("nothing to restore: no items in the backup match the provided selectors")
|
||||||
|
}
|
||||||
|
|
||||||
|
case selectors.ServiceOneDrive:
|
||||||
|
// TODO: Reduce `details` here when we add support for OneDrive restore filters
|
||||||
|
fds = d
|
||||||
|
default:
|
||||||
|
return errors.Errorf("Service %s not supported", op.Selectors.Service)
|
||||||
}
|
}
|
||||||
|
|
||||||
fdsPaths := fds.Paths()
|
fdsPaths := fds.Paths()
|
||||||
|
|||||||
@ -22,6 +22,13 @@ type (
|
|||||||
OneDriveBackup struct {
|
OneDriveBackup struct {
|
||||||
oneDrive
|
oneDrive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OneDriveRestorep provides an api for selecting
|
||||||
|
// data scopes applicable to the OneDrive service,
|
||||||
|
// plus restore-specific methods.
|
||||||
|
OneDriveRestore struct {
|
||||||
|
oneDrive
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewOneDriveBackup produces a new Selector with the service set to ServiceOneDrive.
|
// NewOneDriveBackup produces a new Selector with the service set to ServiceOneDrive.
|
||||||
@ -47,6 +54,29 @@ func (s Selector) ToOneDriveBackup() (*OneDriveBackup, error) {
|
|||||||
return &src, nil
|
return &src, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewOneDriveRestore produces a new Selector with the service set to ServiceOneDrive.
|
||||||
|
func NewOneDriveRestore() *OneDriveRestore {
|
||||||
|
src := OneDriveRestore{
|
||||||
|
oneDrive{
|
||||||
|
newSelector(ServiceOneDrive),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &src
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToOneDriveRestore transforms the generic selector into an OneDriveRestore.
|
||||||
|
// Errors if the service defined by the selector is not ServiceOneDrive.
|
||||||
|
func (s Selector) ToOneDriveRestore() (*OneDriveRestore, error) {
|
||||||
|
if s.Service != ServiceOneDrive {
|
||||||
|
return nil, badCastErr(ServiceOneDrive, s.Service)
|
||||||
|
}
|
||||||
|
|
||||||
|
src := OneDriveRestore{oneDrive{s}}
|
||||||
|
|
||||||
|
return &src, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Printable creates the minimized display of a selector, formatted for human readability.
|
// Printable creates the minimized display of a selector, formatted for human readability.
|
||||||
func (s oneDrive) Printable() Printable {
|
func (s oneDrive) Printable() Printable {
|
||||||
return toPrintable[OneDriveScope](s.Selector)
|
return toPrintable[OneDriveScope](s.Selector)
|
||||||
|
|||||||
@ -157,3 +157,20 @@ func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Exclude_Users() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *OneDriveSelectorSuite) TestNewOneDriveRestore() {
|
||||||
|
t := suite.T()
|
||||||
|
or := NewOneDriveRestore()
|
||||||
|
assert.Equal(t, or.Service, ServiceOneDrive)
|
||||||
|
assert.NotZero(t, or.Scopes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *OneDriveSelectorSuite) TestToOneDriveRestore() {
|
||||||
|
t := suite.T()
|
||||||
|
eb := NewOneDriveRestore()
|
||||||
|
s := eb.Selector
|
||||||
|
or, err := s.ToOneDriveRestore()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, or.Service, ServiceOneDrive)
|
||||||
|
assert.NotZero(t, or.Scopes())
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user