CLI: Commands refactor --> List and Details (#2681)

## Description
Consolidates list and detail commands into one function for the released services.

<!-- Insert PR description-->

---

#### Does this PR need a docs update or release note?

- [x]  No

#### Type of change

<!--- Please check the type of change your PR introduces: --->

- [x] 🧹 Tech Debt/Cleanup

#### Issue(s)

<!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. -->
* related to  #2602<issue>

#### Test Plan

- [x]  Unit test
This commit is contained in:
Danny 2023-03-06 16:09:37 -08:00 committed by GitHub
parent 9cfaf3c140
commit 3f3d47a54a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 149 additions and 258 deletions

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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 <site>'s files from backup 1234abcd-12ab-cd34-56de-1234abcd
corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd --site <site_id>
<<<<<<< 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)