adds the onError option to operations (#347)

* adds the onError option to operations

Adds the OnError option to operations.Options.  OnError tells
corso whether to continue despite concurrent processing
errors, or to exit processing on any error.  Also includes flag
support for setting the option.  Only adds the options, does
not assert error handling behavior in corso.
This commit is contained in:
Keepers 2022-07-19 14:20:12 -06:00 committed by GitHub
parent 6d04c82992
commit 625cf744a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 49 additions and 10 deletions

View File

@ -6,6 +6,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/alcionai/corso/cli/config" "github.com/alcionai/corso/cli/config"
"github.com/alcionai/corso/cli/options"
"github.com/alcionai/corso/cli/print" "github.com/alcionai/corso/cli/print"
"github.com/alcionai/corso/cli/utils" "github.com/alcionai/corso/cli/utils"
"github.com/alcionai/corso/pkg/logger" "github.com/alcionai/corso/pkg/logger"
@ -43,6 +44,7 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
"data", "data",
nil, nil,
"Select one or more types of data to backup: "+dataEmail+", "+dataContacts+", or "+dataEvents) "Select one or more types of data to backup: "+dataEmail+", "+dataContacts+", or "+dataEvents)
options.AddOperationFlags(c)
case listCommand: case listCommand:
c, _ = utils.AddCommand(parent, exchangeListCmd) c, _ = utils.AddCommand(parent, exchangeListCmd)
case detailsCommand: case detailsCommand:
@ -98,7 +100,7 @@ func createExchangeCmd(cmd *cobra.Command, args []string) error {
sel := exchangeBackupCreateSelectors(exchangeAll, user, exchangeData) sel := exchangeBackupCreateSelectors(exchangeAll, user, exchangeData)
bo, err := r.NewBackup(ctx, sel) bo, err := r.NewBackup(ctx, sel, options.OperationOptions())
if err != nil { if err != nil {
return errors.Wrap(err, "Failed to initialize Exchange backup") return errors.Wrap(err, "Failed to initialize Exchange backup")
} }

View File

@ -27,8 +27,8 @@ var corsoCmd = &cobra.Command{
// the root-level flags // the root-level flags
var ( var (
version bool
cfgFile string cfgFile string
version bool
) )
func init() { func init() {

View File

@ -0,0 +1,23 @@
package options
import (
"github.com/alcionai/corso/internal/operations"
"github.com/spf13/cobra"
)
var (
fastFail bool
)
// AddFlags adds the operation option flags
func AddOperationFlags(parent *cobra.Command) {
fs := parent.Flags()
fs.BoolVar(&fastFail, "fast-fail", false, "stop processing immediately if any error occurs")
// TODO: reveal this flag when fail-fast support is implemented
cobra.CheckErr(fs.MarkHidden("fast-fail"))
}
// OperationOptions produces the operation options based on the user's flags.
func OperationOptions() operations.Options {
return operations.NewOptions(fastFail)
}

View File

@ -8,6 +8,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/alcionai/corso/cli/config" "github.com/alcionai/corso/cli/config"
"github.com/alcionai/corso/cli/options"
"github.com/alcionai/corso/cli/utils" "github.com/alcionai/corso/cli/utils"
"github.com/alcionai/corso/pkg/logger" "github.com/alcionai/corso/pkg/logger"
"github.com/alcionai/corso/pkg/repository" "github.com/alcionai/corso/pkg/repository"
@ -37,6 +38,7 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
fs.StringVar(&backupID, "backup", "", "ID of the backup to restore") fs.StringVar(&backupID, "backup", "", "ID of the backup to restore")
cobra.CheckErr(c.MarkFlagRequired("backup")) cobra.CheckErr(c.MarkFlagRequired("backup"))
fs.StringVar(&user, "user", "", "ID of the user whose exchange data will get restored") fs.StringVar(&user, "user", "", "ID of the user whose exchange data will get restored")
options.AddOperationFlags(c)
} }
return c return c
} }
@ -86,7 +88,7 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
} }
defer utils.CloseRepo(ctx, r) defer utils.CloseRepo(ctx, r)
ro, err := r.NewRestore(ctx, backupID, exchangeRestoreSelectors(user, emailFolder, email)) ro, err := r.NewRestore(ctx, backupID, exchangeRestoreSelectors(user, emailFolder, email), options.OperationOptions())
if err != nil { if err != nil {
return errors.Wrap(err, "Failed to initialize Exchange restore") return errors.Wrap(err, "Failed to initialize Exchange restore")
} }

View File

@ -38,8 +38,14 @@ type operation struct {
// Options configure some parameters of the operation // Options configure some parameters of the operation
type Options struct { type Options struct {
FailFast bool `json:"failFast"`
// todo: collision handling // todo: collision handling
// todo: fast fail vs best attempt }
func NewOptions(failFast bool) Options {
return Options{
FailFast: failFast,
}
} }
func newOperation( func newOperation(

View File

@ -128,10 +128,10 @@ func (r *Repository) Close(ctx context.Context) error {
} }
// NewBackup generates a BackupOperation runner. // NewBackup generates a BackupOperation runner.
func (r Repository) NewBackup(ctx context.Context, selector selectors.Selector) (operations.BackupOperation, error) { func (r Repository) NewBackup(ctx context.Context, selector selectors.Selector, opts operations.Options) (operations.BackupOperation, error) {
return operations.NewBackupOperation( return operations.NewBackupOperation(
ctx, ctx,
operations.Options{}, opts,
r.dataLayer, r.dataLayer,
store.NewKopiaStore(r.modelStore), store.NewKopiaStore(r.modelStore),
r.Account, r.Account,
@ -139,10 +139,15 @@ func (r Repository) NewBackup(ctx context.Context, selector selectors.Selector)
} }
// NewRestore generates a restoreOperation runner. // NewRestore generates a restoreOperation runner.
func (r Repository) NewRestore(ctx context.Context, backupID string, sel selectors.Selector) (operations.RestoreOperation, error) { func (r Repository) NewRestore(
ctx context.Context,
backupID string,
sel selectors.Selector,
opts operations.Options,
) (operations.RestoreOperation, error) {
return operations.NewRestoreOperation( return operations.NewRestoreOperation(
ctx, ctx,
operations.Options{}, opts,
r.dataLayer, r.dataLayer,
store.NewKopiaStore(r.modelStore), store.NewKopiaStore(r.modelStore),
r.Account, r.Account,

View File

@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/alcionai/corso/internal/operations"
ctesting "github.com/alcionai/corso/internal/testing" ctesting "github.com/alcionai/corso/internal/testing"
"github.com/alcionai/corso/pkg/account" "github.com/alcionai/corso/pkg/account"
"github.com/alcionai/corso/pkg/repository" "github.com/alcionai/corso/pkg/repository"
@ -171,7 +172,7 @@ func (suite *RepositoryIntegrationSuite) TestNewBackup() {
r, err := repository.Initialize(ctx, acct, st) r, err := repository.Initialize(ctx, acct, st)
require.NoError(t, err) require.NoError(t, err)
bo, err := r.NewBackup(ctx, selectors.Selector{}) bo, err := r.NewBackup(ctx, selectors.Selector{}, operations.Options{})
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, bo) require.NotNil(t, bo)
} }
@ -190,7 +191,7 @@ func (suite *RepositoryIntegrationSuite) TestNewRestore() {
r, err := repository.Initialize(ctx, acct, st) r, err := repository.Initialize(ctx, acct, st)
require.NoError(t, err) require.NoError(t, err)
ro, err := r.NewRestore(ctx, "backup-id", selectors.Selector{}) ro, err := r.NewRestore(ctx, "backup-id", selectors.Selector{}, operations.Options{})
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, ro) require.NotNil(t, ro)
} }