From 3f3d47a54a9f154aa6ac4bc4ff0eff450d9acb5d Mon Sep 17 00:00:00 2001 From: Danny Date: Mon, 6 Mar 2023 16:09:37 -0800 Subject: [PATCH] CLI: Commands refactor --> List and Details (#2681) ## Description Consolidates list and detail commands into one function for the released services. --- #### Does this PR need a docs update or release note? - [x] :no_entry: No #### Type of change - [x] :broom: Tech Debt/Cleanup #### Issue(s) * related to #2602 #### Test Plan - [x] :zap: Unit test --- src/cli/backup/backup.go | 104 +++++++++++++++++++++++++++++++ src/cli/backup/exchange.go | 86 +++----------------------- src/cli/backup/onedrive.go | 101 +++++------------------------- src/cli/backup/sharepoint.go | 116 ++++++++--------------------------- 4 files changed, 149 insertions(+), 258 deletions(-) diff --git a/src/cli/backup/backup.go b/src/cli/backup/backup.go index ed7c3a441..0cb72c792 100644 --- a/src/cli/backup/backup.go +++ b/src/cli/backup/backup.go @@ -1,9 +1,37 @@ package backup import ( + "context" + + "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/data" + "github.com/alcionai/corso/src/internal/model" + "github.com/alcionai/corso/src/pkg/account" + "github.com/alcionai/corso/src/pkg/backup" + "github.com/alcionai/corso/src/pkg/path" + "github.com/alcionai/corso/src/pkg/repository" + "github.com/alcionai/corso/src/pkg/store" + "github.com/pkg/errors" "github.com/spf13/cobra" ) +// ============================================== +// Folder Object flags +// These options are flags for indicating +// that a time-based filter should be used for +// within returning objects for details. +// Used by: OneDrive, SharePoint +// ================================================ +var ( + fileCreatedAfter string + fileCreatedBefore string + fileModifiedAfter string + fileModifiedBefore string +) + var subCommandFuncs = []func() *cobra.Command{ createCmd, listCmd, @@ -125,3 +153,79 @@ func deleteCmd() *cobra.Command { func handleDeleteCmd(cmd *cobra.Command, args []string) error { return cmd.Help() } + +// genericDeleteCommand is a helper function that all services can use +// for the removal of an entry from the repository +func genericDeleteCommand(cmd *cobra.Command, bID, designation string, args []string) error { + ctx := cmd.Context() + + if utils.HasNoFlagsAndShownHelp(cmd) { + return nil + } + + r, _, err := getAccountAndConnect(ctx) + if err != nil { + return Only(ctx, err) + } + + defer utils.CloseRepo(ctx, r) + + if err := r.DeleteBackup(ctx, model.StableID(bID)); err != nil { + return Only(ctx, errors.Wrapf(err, "Deleting backup %s", bID)) + } + + Infof(ctx, "Deleted %s backup %s", designation, bID) + + return nil +} + +// genericListCommand is a helper function that all services can use +// to display the backup IDs saved within the repository +func genericListCommand(cmd *cobra.Command, bID string, service path.ServiceType, args []string) error { + ctx := cmd.Context() + + r, _, err := getAccountAndConnect(ctx) + if err != nil { + return Only(ctx, err) + } + + defer utils.CloseRepo(ctx, r) + + if len(backupID) > 0 { + b, err := r.Backup(ctx, model.StableID(bID)) + if err != nil { + if errors.Is(err, data.ErrNotFound) { + return Only(ctx, errors.Errorf("No backup exists with the id %s", bID)) + } + + return Only(ctx, errors.Wrap(err, "Failed to find backup "+bID)) + } + + b.Print(ctx) + + return nil + } + + bs, err := r.BackupsByTag(ctx, store.Service(service)) + if err != nil { + return Only(ctx, errors.Wrap(err, "Failed to list backups in the repository")) + } + + backup.PrintAll(ctx, bs) + + return nil +} + +func getAccountAndConnect(ctx context.Context) (repository.Repository, *account.Account, error) { + cfg, err := config.GetConfigRepoDetails(ctx, true, nil) + if err != nil { + return nil, nil, err + } + + r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) + if err != nil { + return nil, nil, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider) + } + + return r, &cfg.Account, nil +} diff --git a/src/cli/backup/exchange.go b/src/cli/backup/exchange.go index 42b6456fd..04d9f5b6c 100644 --- a/src/cli/backup/exchange.go +++ b/src/cli/backup/exchange.go @@ -8,7 +8,6 @@ import ( "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" @@ -21,7 +20,6 @@ import ( "github.com/alcionai/corso/src/pkg/repository" "github.com/alcionai/corso/src/pkg/selectors" "github.com/alcionai/corso/src/pkg/services/m365" - "github.com/alcionai/corso/src/pkg/store" ) // ------------------------------------------------------------------------------------------------ @@ -260,16 +258,11 @@ func createExchangeCmd(cmd *cobra.Command, args []string) error { return err } - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) + r, acct, err := getAccountAndConnect(ctx) if err != nil { return Only(ctx, err) } - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider)) - } - defer utils.CloseRepo(ctx, r) sel := exchangeBackupCreateSelectors(user, exchangeData) @@ -277,7 +270,7 @@ func createExchangeCmd(cmd *cobra.Command, args []string) error { // TODO: log/print recoverable errors errs := fault.New(false) - users, err := m365.UserPNs(ctx, cfg.Account, errs) + users, err := m365.UserPNs(ctx, *acct, errs) if err != nil { return Only(ctx, errors.Wrap(err, "Failed to retrieve M365 user(s)")) } @@ -382,43 +375,7 @@ func exchangeListCmd() *cobra.Command { // lists the history of backup operations func listExchangeCmd(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) - if err != nil { - return Only(ctx, err) - } - - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider)) - } - - defer utils.CloseRepo(ctx, r) - - if len(backupID) > 0 { - b, err := r.Backup(ctx, model.StableID(backupID)) - if err != nil { - if errors.Is(err, data.ErrNotFound) { - return Only(ctx, errors.Errorf("No backup exists with the id %s", backupID)) - } - - return Only(ctx, errors.Wrap(err, "Failed to find backup "+backupID)) - } - - b.Print(ctx) - - return nil - } - - bs, err := r.BackupsByTag(ctx, store.Service(path.ExchangeService)) - if err != nil { - return Only(ctx, errors.Wrap(err, "Failed to list backups in the repository")) - } - - backup.PrintAll(ctx, bs) - - return nil + return genericListCommand(cmd, backupID, path.ExchangeService, args) } // ------------------------------------------------------------------------------------------------ @@ -465,20 +422,15 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error { Populated: utils.GetPopulatedFlags(cmd), } - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) + r, _, err := getAccountAndConnect(ctx) if err != nil { return Only(ctx, err) } - ctrlOpts := options.Control() - - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, ctrlOpts) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider)) - } - defer utils.CloseRepo(ctx, r) + ctrlOpts := options.Control() + ds, err := runDetailsExchangeCmd(ctx, r, backupID, opts, ctrlOpts.SkipReduce) if err != nil { return Only(ctx, err) @@ -543,29 +495,5 @@ func exchangeDeleteCmd() *cobra.Command { // deletes an exchange service backup. func deleteExchangeCmd(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - - if utils.HasNoFlagsAndShownHelp(cmd) { - return nil - } - - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) - if err != nil { - return Only(ctx, err) - } - - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.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)) - } - - Info(ctx, "Deleted Exchange backup ", backupID) - - return nil + return genericDeleteCommand(cmd, backupID, "Exchange", args) } diff --git a/src/cli/backup/onedrive.go b/src/cli/backup/onedrive.go index c79fc32a7..fb9c0c57f 100644 --- a/src/cli/backup/onedrive.go +++ b/src/cli/backup/onedrive.go @@ -8,7 +8,6 @@ import ( "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" @@ -21,7 +20,6 @@ import ( "github.com/alcionai/corso/src/pkg/repository" "github.com/alcionai/corso/src/pkg/selectors" "github.com/alcionai/corso/src/pkg/services/m365" - "github.com/alcionai/corso/src/pkg/store" ) // ------------------------------------------------------------------------------------------------ @@ -179,16 +177,11 @@ func createOneDriveCmd(cmd *cobra.Command, args []string) error { return err } - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) + r, acct, err := getAccountAndConnect(ctx) if err != nil { return Only(ctx, err) } - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider)) - } - defer utils.CloseRepo(ctx, r) sel := oneDriveBackupCreateSelectors(user) @@ -196,7 +189,7 @@ func createOneDriveCmd(cmd *cobra.Command, args []string) error { // TODO: log/print recoverable errors errs := fault.New(false) - users, err := m365.UserPNs(ctx, cfg.Account, errs) + users, err := m365.UserPNs(ctx, *acct, errs) if err != nil { return Only(ctx, errors.Wrap(err, "Failed to retrieve M365 users")) } @@ -278,43 +271,7 @@ func oneDriveListCmd() *cobra.Command { // lists the history of backup operations func listOneDriveCmd(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) - if err != nil { - return Only(ctx, err) - } - - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider)) - } - - defer utils.CloseRepo(ctx, r) - - if len(backupID) > 0 { - b, err := r.Backup(ctx, model.StableID(backupID)) - if err != nil { - if errors.Is(err, data.ErrNotFound) { - return Only(ctx, errors.Errorf("No backup exists with the id %s", backupID)) - } - - return Only(ctx, errors.Wrap(err, "Failed to find backup "+backupID)) - } - - b.Print(ctx) - - return nil - } - - bs, err := r.BackupsByTag(ctx, store.Service(path.OneDriveService)) - if err != nil { - return Only(ctx, errors.Wrap(err, "Failed to list backups in the repository")) - } - - backup.PrintAll(ctx, bs) - - return nil + return genericListCommand(cmd, backupID, path.OneDriveService, args) } // ------------------------------------------------------------------------------------------------ @@ -334,26 +291,11 @@ func oneDriveDetailsCmd() *cobra.Command { // prints the item details for a given backup func detailsOneDriveCmd(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - if utils.HasNoFlagsAndShownHelp(cmd) { return nil } - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) - if err != nil { - return Only(ctx, err) - } - - ctrlOpts := options.Control() - - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, ctrlOpts) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider)) - } - - defer utils.CloseRepo(ctx, r) - + ctx := cmd.Context() opts := utils.OneDriveOpts{ Users: user, Names: fileNames, @@ -366,6 +308,15 @@ func detailsOneDriveCmd(cmd *cobra.Command, args []string) error { Populated: utils.GetPopulatedFlags(cmd), } + r, _, err := getAccountAndConnect(ctx) + if err != nil { + return Only(ctx, err) + } + + defer utils.CloseRepo(ctx, r) + + ctrlOpts := options.Control() + ds, err := runDetailsOneDriveCmd(ctx, r, backupID, opts, ctrlOpts.SkipReduce) if err != nil { return Only(ctx, err) @@ -427,29 +378,5 @@ func oneDriveDeleteCmd() *cobra.Command { // deletes a oneDrive service backup. func deleteOneDriveCmd(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - - if utils.HasNoFlagsAndShownHelp(cmd) { - return nil - } - - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) - if err != nil { - return Only(ctx, err) - } - - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.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)) - } - - Info(ctx, "Deleted OneDrive backup ", backupID) - - return nil + return genericDeleteCommand(cmd, backupID, "OneDrive", args) } diff --git a/src/cli/backup/sharepoint.go b/src/cli/backup/sharepoint.go index f5ed1bd87..22b57846e 100644 --- a/src/cli/backup/sharepoint.go +++ b/src/cli/backup/sharepoint.go @@ -8,7 +8,6 @@ import ( "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" @@ -22,7 +21,6 @@ import ( "github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/repository" "github.com/alcionai/corso/src/pkg/selectors" - "github.com/alcionai/corso/src/pkg/store" ) // ------------------------------------------------------------------------------------------------ @@ -71,7 +69,11 @@ corso backup delete sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd` sharePointServiceCommandDetailsExamples = `# Explore 's files from backup 1234abcd-12ab-cd34-56de-1234abcd corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd --site +<<<<<<< HEAD +# Explore site's files created before end of 2015 from a specific backup +======= # Find all site files that were created before a certain date. +>>>>>>> main corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \ --web-url https://example.com --file-created-before 2015-01-01T00:00:00 ` @@ -219,22 +221,17 @@ func createSharePointCmd(cmd *cobra.Command, args []string) error { return err } - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) + r, acct, err := getAccountAndConnect(ctx) if err != nil { return Only(ctx, err) } - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider)) - } - defer utils.CloseRepo(ctx, r) // TODO: log/print recoverable errors errs := fault.New(false) - gc, err := connector.NewGraphConnector(ctx, graph.HTTPClient(graph.NoTimeout()), cfg.Account, connector.Sites, errs) + gc, err := connector.NewGraphConnector(ctx, graph.HTTPClient(graph.NoTimeout()), *acct, connector.Sites, errs) if err != nil { return Only(ctx, errors.Wrap(err, "Failed to connect to Microsoft APIs")) } @@ -388,43 +385,7 @@ func sharePointListCmd() *cobra.Command { // lists the history of backup operations func listSharePointCmd(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) - if err != nil { - return Only(ctx, err) - } - - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider)) - } - - defer utils.CloseRepo(ctx, r) - - if len(backupID) > 0 { - b, err := r.Backup(ctx, model.StableID(backupID)) - if err != nil { - if errors.Is(err, data.ErrNotFound) { - return Only(ctx, errors.Errorf("No backup exists with the id %s", backupID)) - } - - return Only(ctx, errors.Wrap(err, "Failed to find backup "+backupID)) - } - - b.Print(ctx) - - return nil - } - - bs, err := r.BackupsByTag(ctx, store.Service(path.SharePointService)) - if err != nil { - return Only(ctx, errors.Wrap(err, "Failed to list backups in the repository")) - } - - backup.PrintAll(ctx, bs) - - return nil + return genericListCommand(cmd, backupID, path.SharePointService, args) } // ------------------------------------------------------------------------------------------------ @@ -444,31 +405,7 @@ func sharePointDeleteCmd() *cobra.Command { // deletes a sharePoint service backup. func deleteSharePointCmd(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - - if utils.HasNoFlagsAndShownHelp(cmd) { - return nil - } - - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) - if err != nil { - return Only(ctx, err) - } - - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control()) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.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)) - } - - Info(ctx, "Deleted SharePoint backup ", backupID) - - return nil + return genericDeleteCommand(cmd, backupID, "SharePoint", args) } // ------------------------------------------------------------------------------------------------ @@ -488,38 +425,33 @@ func sharePointDetailsCmd() *cobra.Command { // lists the history of backup operations func detailsSharePointCmd(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - if utils.HasNoFlagsAndShownHelp(cmd) { return nil } - cfg, err := config.GetConfigRepoDetails(ctx, true, nil) - if err != nil { - return Only(ctx, err) - } - - ctrlOpts := options.Control() - - r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, ctrlOpts) - if err != nil { - return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", cfg.Storage.Provider)) - } - - defer utils.CloseRepo(ctx, r) - + ctx := cmd.Context() opts := utils.SharePointOpts{ LibraryItems: libraryItems, LibraryPaths: libraryPaths, Sites: site, WebURLs: weburl, - FileCreatedAfter: utils.FileCreatedAfter, - FileCreatedBefore: utils.FileCreatedBefore, - FileModifiedAfter: utils.FileModifiedAfter, - FileModifiedBefore: utils.FileModifiedBefore, - Populated: utils.GetPopulatedFlags(cmd), + FileCreatedAfter: fileCreatedAfter, + FileCreatedBefore: fileCreatedBefore, + FileModifiedAfter: fileModifiedAfter, + FileModifiedBefore: fileModifiedBefore, + + Populated: utils.GetPopulatedFlags(cmd), } + r, _, err := getAccountAndConnect(ctx) + if err != nil { + return Only(ctx, err) + } + + defer utils.CloseRepo(ctx, r) + + ctrlOpts := options.Control() + ds, err := runDetailsSharePointCmd(ctx, r, backupID, opts, ctrlOpts.SkipReduce) if err != nil { return Only(ctx, err)