Fix wsl errors in cmd and cli packages (#651)

This commit is contained in:
ashmrtn 2022-08-26 09:13:39 -07:00 committed by GitHub
parent f24ad6ccbd
commit 88a318a7c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 145 additions and 14 deletions

View File

@ -18,6 +18,7 @@ var serviceCommands = []func(parent *cobra.Command) *cobra.Command{
// AddCommands attaches all `corso backup * *` commands to the parent.
func AddCommands(parent *cobra.Command) {
parent.AddCommand(backupCmd)
for _, sc := range subCommands {
backupCmd.AddCommand(sc)
}

View File

@ -53,7 +53,6 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
)
switch parent.Use {
case createCommand:
c, fs = utils.AddCommand(parent, exchangeCreateCmd())
fs.StringSliceVar(
@ -191,6 +190,7 @@ func createExchangeCmd(cmd *cobra.Command, args []string) error {
if err != nil {
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
}
defer utils.CloseRepo(ctx, r)
sel := exchangeBackupCreateSelectors(exchangeAll, user, exchangeData)
@ -211,6 +211,7 @@ func createExchangeCmd(cmd *cobra.Command, args []string) error {
}
bu.Print(ctx)
return nil
}
@ -220,11 +221,13 @@ func exchangeBackupCreateSelectors(all bool, users, data []string) selectors.Sel
sel.Include(sel.Users(selectors.Any()))
return sel.Selector
}
if len(data) == 0 {
sel.Include(sel.ContactFolders(user, selectors.Any()))
sel.Include(sel.MailFolders(user, selectors.Any()))
sel.Include(sel.Events(user, selectors.Any()))
}
for _, d := range data {
switch d {
case dataContacts:
@ -235,6 +238,7 @@ func exchangeBackupCreateSelectors(all bool, users, data []string) selectors.Sel
sel.Include(sel.Events(users, selectors.Any()))
}
}
return sel.Selector
}
@ -242,15 +246,18 @@ func validateExchangeBackupCreateFlags(all bool, users, data []string) error {
if len(users) == 0 && !all {
return errors.New("requires one or more --user ids, the wildcard --user *, or the --all flag")
}
if len(data) > 0 && all {
return errors.New("--all does a backup on all data, and cannot be reduced with --data")
}
for _, d := range data {
if d != dataContacts && d != dataEmail && d != dataEvents {
return errors.New(
d + " is an unrecognized data type; must be one of " + dataContacts + ", " + dataEmail + ", or " + dataEvents)
}
}
return nil
}
@ -290,6 +297,7 @@ func listExchangeCmd(cmd *cobra.Command, args []string) error {
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)
@ -298,6 +306,7 @@ func listExchangeCmd(cmd *cobra.Command, args []string) error {
}
backup.PrintAll(ctx, bs)
return nil
}
@ -353,6 +362,7 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
if err != nil {
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
}
defer utils.CloseRepo(ctx, r)
d, _, err := r.BackupDetails(ctx, backupID)
@ -387,6 +397,7 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
}
ds.PrintEntries(ctx)
return nil
}
@ -420,6 +431,7 @@ func includeExchangeContacts(sel *selectors.ExchangeRestore, users, contactFolde
if len(contactFolders) == 0 {
return
}
if len(contacts) > 0 {
sel.Include(sel.Contacts(users, contactFolders, contacts))
} else {
@ -431,6 +443,7 @@ func includeExchangeEmails(sel *selectors.ExchangeRestore, users, emailFolders,
if len(emailFolders) == 0 {
return
}
if len(emails) > 0 {
sel.Include(sel.Mails(users, emailFolders, emails))
} else {
@ -442,6 +455,7 @@ func includeExchangeEvents(sel *selectors.ExchangeRestore, users, events []strin
if len(events) == 0 {
return
}
sel.Include(sel.Events(users, events))
}
@ -460,6 +474,7 @@ func filterExchangeInfoMailReceivedAfter(sel *selectors.ExchangeRestore, receive
if len(receivedAfter) == 0 {
return
}
sel.Filter(sel.MailReceivedAfter(receivedAfter))
}
@ -467,6 +482,7 @@ func filterExchangeInfoMailReceivedBefore(sel *selectors.ExchangeRestore, receiv
if len(receivedBefore) == 0 {
return
}
sel.Filter(sel.MailReceivedBefore(receivedBefore))
}
@ -474,6 +490,7 @@ func filterExchangeInfoMailSender(sel *selectors.ExchangeRestore, sender string)
if len(sender) == 0 {
return
}
sel.Filter(sel.MailSender([]string{sender}))
}
@ -481,6 +498,7 @@ func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject strin
if len(subject) == 0 {
return
}
sel.Filter(sel.MailSubject([]string{subject}))
}
@ -492,24 +510,30 @@ func validateExchangeBackupDetailFlags(
if len(backupID) == 0 {
return errors.New("a backup ID is required")
}
lu := len(users)
lc, lcf := len(contacts), len(contactFolders)
le, lef := len(emails), len(emailFolders)
lev := len(events)
if lu+lc+lcf+le+lef+lev == 0 {
return nil
}
if lu == 0 {
return errors.New("requires one or more --user ids, the wildcard --user *, or the --all flag")
}
if lc > 0 && lcf == 0 {
return errors.New(
"one or more --contact-folder ids or the wildcard --contact-folder * must be included to specify a --contact")
}
if le > 0 && lef == 0 {
return errors.New(
"one or more --email-folder ids or the wildcard --email-folder * must be included to specify a --email")
}
return nil
}
@ -555,6 +579,7 @@ func deleteExchangeCmd(cmd *cobra.Command, args []string) error {
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 {

View File

@ -46,6 +46,7 @@ func TestBackupExchangeIntegrationSuite(t *testing.T) {
); err != nil {
t.Skip(err)
}
suite.Run(t, new(BackupExchangeIntegrationSuite))
}
@ -70,8 +71,8 @@ func (suite *BackupExchangeIntegrationSuite) SetupSuite() {
}
suite.vpr, suite.cfgFP, err = tester.MakeTempTestConfigClone(t, force)
require.NoError(t, err)
ctx := config.SetViper(tester.NewContext(), suite.vpr)
ctx := config.SetViper(tester.NewContext(), suite.vpr)
suite.m365UserID = tester.M365UserID(t)
// init the repo first
@ -89,8 +90,10 @@ func (suite *BackupExchangeIntegrationSuite) TestExchangeBackupCmd() {
"--user", suite.m365UserID,
"--data", "email")
cli.BuildCommandTree(cmd)
var recorder strings.Builder
recorder := strings.Builder{}
cmd.SetOut(&recorder)
ctx = print.SetRootCmd(ctx, cmd)
// run the command
@ -126,6 +129,7 @@ func TestPreparedBackupExchangeIntegrationSuite(t *testing.T) {
); err != nil {
t.Skip(err)
}
suite.Run(t, new(PreparedBackupExchangeIntegrationSuite))
}
@ -150,8 +154,8 @@ func (suite *PreparedBackupExchangeIntegrationSuite) SetupSuite() {
}
suite.vpr, suite.cfgFP, err = tester.MakeTempTestConfigClone(t, force)
require.NoError(t, err)
ctx := config.SetViper(tester.NewContext(), suite.vpr)
ctx := config.SetViper(tester.NewContext(), suite.vpr)
suite.m365UserID = tester.M365UserID(t)
// init the repo first
@ -178,8 +182,10 @@ func (suite *PreparedBackupExchangeIntegrationSuite) TestExchangeListCmd() {
"backup", "list", "exchange",
"--config-file", suite.cfgFP)
cli.BuildCommandTree(cmd)
var recorder strings.Builder
recorder := strings.Builder{}
cmd.SetOut(&recorder)
ctx = print.SetRootCmd(ctx, cmd)
// run the command
@ -203,8 +209,10 @@ func (suite *PreparedBackupExchangeIntegrationSuite) TestExchangeDetailsCmd() {
"--config-file", suite.cfgFP,
"--backup", string(suite.backupOp.Results.BackupID))
cli.BuildCommandTree(cmd)
var recorder strings.Builder
recorder := strings.Builder{}
cmd.SetOut(&recorder)
ctx = print.SetRootCmd(ctx, cmd)
// run the command
@ -212,6 +220,7 @@ func (suite *PreparedBackupExchangeIntegrationSuite) TestExchangeDetailsCmd() {
// compare the output
result := recorder.String()
for i, ent := range deets.Entries {
t.Run(fmt.Sprintf("detail %d", i), func(t *testing.T) {
assert.Contains(t, result, ent.RepoRef)
@ -241,6 +250,7 @@ func TestBackupDeleteExchangeIntegrationSuite(t *testing.T) {
); err != nil {
t.Skip(err)
}
suite.Run(t, new(BackupDeleteExchangeIntegrationSuite))
}
@ -265,6 +275,7 @@ func (suite *BackupDeleteExchangeIntegrationSuite) SetupSuite() {
}
suite.vpr, suite.cfgFP, err = tester.MakeTempTestConfigClone(t, force)
require.NoError(t, err)
ctx := config.SetViper(tester.NewContext(), suite.vpr)
// init the repo first

View File

@ -23,6 +23,7 @@ func TestExchangeSuite(t *testing.T) {
func (suite *ExchangeSuite) TestAddExchangeCommands() {
expectUse := exchangeServiceCommand
table := []struct {
name string
use string
@ -217,6 +218,7 @@ func (suite *ExchangeSuite) TestExchangeBackupCreateSelectors() {
func (suite *ExchangeSuite) TestValidateBackupDetailFlags() {
stub := []string{"id-stub"}
table := []struct {
name string
contacts, contactFolders, emails, emailFolders, events, users []string
@ -302,6 +304,7 @@ func (suite *ExchangeSuite) TestValidateBackupDetailFlags() {
func (suite *ExchangeSuite) TestIncludeExchangeBackupDetailDataSelectors() {
stub := []string{"id-stub"}
a := []string{utils.Wildcard}
table := []struct {
name string
contacts, contactFolders, emails, emailFolders, events, users []string
@ -484,6 +487,7 @@ func (suite *ExchangeSuite) TestIncludeExchangeBackupDetailDataSelectors() {
func (suite *ExchangeSuite) TestFilterExchangeBackupDetailInfoSelectors() {
stub := "id-stub"
a := utils.Wildcard
table := []struct {
name string
after, before, sender, subject string

View File

@ -41,6 +41,7 @@ func handleCorsoCmd(cmd *cobra.Command, args []string) error {
print.Infof(cmd.Context(), "Corso\nversion:\tpre-alpha\n")
return nil
}
return cmd.Help()
}
@ -50,6 +51,7 @@ func CorsoCommand() *cobra.Command {
c := &cobra.Command{}
*c = *corsoCmd
BuildCommandTree(c)
return c
}

View File

@ -22,6 +22,7 @@ func m365ConfigsFromViper(vpr *viper.Viper) (account.M365Config, error) {
}
m365.TenantID = vpr.GetString(TenantIDKey)
return m365, nil
}

View File

@ -34,10 +34,12 @@ var configFilePath string
// adds the persistent flag --config-file to the provided command.
func AddConfigFlags(cmd *cobra.Command) {
fs := cmd.PersistentFlags()
homeDir, err := os.UserHomeDir()
if err != nil {
Err(cmd.Context(), "finding $HOME directory (default) for config file")
}
fs.StringVar(
&configFilePath,
"config-file",
@ -57,6 +59,7 @@ func InitFunc() func(*cobra.Command, []string) error {
if err != nil {
return err
}
return Read(cmd.Context())
}
}
@ -76,6 +79,7 @@ func initWithViper(vpr *viper.Viper, configFP string) error {
vpr.AddConfigPath(home)
vpr.SetConfigType("toml")
vpr.SetConfigName(".corso")
return nil
}
@ -85,11 +89,12 @@ func initWithViper(vpr *viper.Viper, configFP string) error {
// work correctly (it does not use the configured file)
vpr.AddConfigPath(path.Dir(configFP))
fileName := path.Base(configFP)
ext := path.Ext(configFP)
if len(ext) == 0 {
return errors.New("config file requires an extension e.g. `toml`")
}
fileName := path.Base(configFP)
fileName = strings.TrimSuffix(fileName, ext)
vpr.SetConfigType(strings.TrimPrefix(ext, "."))
vpr.SetConfigName(fileName)
@ -110,6 +115,7 @@ func SetViper(ctx context.Context, vpr *viper.Viper) context.Context {
if vpr == nil {
vpr = viper.GetViper()
}
return context.WithValue(ctx, viperCtx{}, vpr)
}
@ -118,10 +124,12 @@ func SetViper(ctx context.Context, vpr *viper.Viper) context.Context {
// (global) viper instance.
func GetViper(ctx context.Context) *viper.Viper {
vprIface := ctx.Value(viperCtx{})
vpr, ok := vprIface.(*viper.Viper)
if vpr == nil || !ok {
return viper.GetViper()
}
return vpr
}
@ -137,6 +145,7 @@ func Read(ctx context.Context) error {
logger.Ctx(ctx).Debugw("found config file", "configFile", viper.ConfigFileUsed())
return err
}
return nil
}
@ -163,8 +172,10 @@ func writeRepoConfigWithViper(vpr *viper.Viper, s3Config storage.S3Config, m365C
if _, ok := err.(viper.ConfigFileAlreadyExistsError); ok {
return vpr.WriteConfig()
}
return err
}
return nil
}
@ -200,6 +211,7 @@ func getStorageAndAccountWithViper(
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return store, acct, errors.Wrap(err, "reading corso config file: "+vpr.ConfigFileUsed())
}
readConfigFromViper = false
}
}
@ -238,14 +250,17 @@ func mustMatchConfig(vpr *viper.Viper, m map[string]string) error {
if len(v) == 0 {
continue // empty variables will get caught by configuration validators, if necessary
}
tomlK, ok := constToTomlKeyMap[k]
if !ok {
continue // m may declare values which aren't stored in the config file
}
vv := vpr.GetString(tomlK)
if v != vv {
return errors.New("value of " + k + " (" + v + ") does not match corso configuration value (" + vv + ")")
}
}
return nil
}

View File

@ -190,6 +190,7 @@ func TestConfigIntegrationSuite(t *testing.T) {
); err != nil {
t.Skip(err)
}
suite.Run(t, new(ConfigIntegrationSuite))
}

View File

@ -25,6 +25,7 @@ func s3ConfigsFromViper(vpr *viper.Viper) (storage.S3Config, error) {
s3Config.Bucket = vpr.GetString(BucketNameKey)
s3Config.Endpoint = vpr.GetString(EndpointKey)
s3Config.Prefix = vpr.GetString(PrefixKey)
return s3Config, nil
}
@ -78,6 +79,7 @@ func configureStorage(
if err := corso.Validate(); err != nil {
return store, errors.Wrap(err, "validating corso credentials")
}
cCfg := storage.CommonConfig{
Corso: corso,
}

View File

@ -22,6 +22,7 @@ func envCmd() *cobra.Command {
Args: cobra.NoArgs,
}
envCmd.SetHelpFunc(envGuide)
return envCmd
}
@ -81,6 +82,7 @@ func toPrintable(evs []envVar) []Printable {
for _, ev := range evs {
ps = append(ps, ev)
}
return ps
}

View File

@ -24,6 +24,7 @@ func (suite *EnvSuite) TestAddEnvCommands() {
cmd := &cobra.Command{Use: "root"}
AddCommands(cmd)
c := envCmd()
require.NotNil(t, c)

View File

@ -30,9 +30,11 @@ func SetRootCmd(ctx context.Context, root *cobra.Command) context.Context {
func getRootCmd(ctx context.Context) *cobra.Command {
cmdIface := ctx.Value(rootCmdCtx{})
cmd, ok := cmdIface.(*cobra.Command)
if cmd == nil || !ok {
return &cobra.Command{}
}
return cmd
}
@ -67,6 +69,7 @@ func err(w io.Writer, s ...any) {
if len(s) == 0 {
return
}
msg := append([]any{"Error: "}, s...)
fmt.Fprint(w, msg...)
}
@ -82,6 +85,7 @@ func info(w io.Writer, s ...any) {
if len(s) == 0 {
return
}
fmt.Fprint(w, s...)
fmt.Fprintf(w, "\n")
}
@ -97,6 +101,7 @@ func infof(w io.Writer, t string, s ...any) {
if len(t) == 0 {
return
}
fmt.Fprintf(w, t, s...)
fmt.Fprintf(w, "\n")
}
@ -129,6 +134,7 @@ func print(w io.Writer, p Printable) {
outputJSON(w, p, outputAsJSONDebug)
return
}
outputTable(w, []Printable{p})
}
@ -144,10 +150,12 @@ func printAll(w io.Writer, ps []Printable) {
if len(ps) == 0 {
return
}
if outputAsJSON || outputAsJSONDebug {
outputJSONArr(w, ps, outputAsJSONDebug)
return
}
outputTable(w, ps)
}
@ -167,9 +175,11 @@ func outputTable(w io.Writer, ps []Printable) {
Headers: ps[0].Headers(),
Rows: [][]string{},
}
for _, p := range ps {
t.Rows = append(t.Rows, p.Values())
}
_ = t.WriteTable(
w,
&table.Config{
@ -188,11 +198,13 @@ func outputJSON(w io.Writer, p Printable, debug bool) {
printJSON(w, p)
return
}
printJSON(w, p.MinimumPrintable())
}
func outputJSONArr(w io.Writer, ps []Printable, debug bool) {
sl := make([]any, 0, len(ps))
for _, p := range ps {
if debug {
sl = append(sl, p)
@ -200,6 +212,7 @@ func outputJSONArr(w io.Writer, ps []Printable, debug bool) {
sl = append(sl, p.MinimumPrintable())
}
}
printJSON(w, sl)
}
@ -210,5 +223,6 @@ func printJSON(w io.Writer, a any) {
fmt.Fprintf(w, "error formatting results to json: %v\n", err)
return
}
fmt.Fprintln(w, string(pretty.Pretty(bs)))
}

View File

@ -30,8 +30,9 @@ func (suite *PrintUnitSuite) TestOnly() {
func (suite *PrintUnitSuite) TestErr() {
t := suite.T()
var b bytes.Buffer
b := bytes.Buffer{}
msg := "I have seen the fnords!"
err(&b, msg)
assert.Contains(t, b.String(), "Error: ")
assert.Contains(t, b.String(), msg)
@ -39,17 +40,19 @@ func (suite *PrintUnitSuite) TestErr() {
func (suite *PrintUnitSuite) TestInfo() {
t := suite.T()
var b bytes.Buffer
b := bytes.Buffer{}
msg := "I have seen the fnords!"
info(&b, msg)
assert.Contains(t, b.String(), msg)
}
func (suite *PrintUnitSuite) TestInfof() {
t := suite.T()
var b bytes.Buffer
b := bytes.Buffer{}
msg := "I have seen the fnords!"
msg2 := "smarf"
infof(&b, msg, msg2)
bs := b.String()
assert.Contains(t, bs, msg)

View File

@ -31,6 +31,7 @@ func addS3Commands(parent *cobra.Command) *cobra.Command {
c *cobra.Command
fs *pflag.FlagSet
)
switch parent.Use {
case initCommand:
c, fs = utils.AddCommand(parent, s3InitCmd())
@ -47,6 +48,7 @@ func addS3Commands(parent *cobra.Command) *cobra.Command {
// In general, we don't want to expose this flag to users and have them mistake it
// for a broad-scale idempotency solution. We can un-hide it later the need arises.
cobra.CheckErr(fs.MarkHidden("succeed-if-exists"))
return c
}
@ -80,6 +82,7 @@ func initS3Cmd(cmd *cobra.Command, args []string) error {
if err != nil {
return Only(ctx, err)
}
s3Cfg, err := s.S3Config()
if err != nil {
return Only(ctx, errors.Wrap(err, "Retrieving s3 configuration"))
@ -103,8 +106,10 @@ func initS3Cmd(cmd *cobra.Command, args []string) error {
if succeedIfExists && kopia.IsRepoAlreadyExistsError(err) {
return nil
}
return Only(ctx, errors.Wrap(err, "Failed to initialize a new S3 repository"))
}
defer utils.CloseRepo(ctx, r)
Infof(ctx, "Initialized a S3 repository within bucket %s.", s3Cfg.Bucket)
@ -112,6 +117,7 @@ func initS3Cmd(cmd *cobra.Command, args []string) error {
if err = config.WriteRepoConfig(ctx, s3Cfg, m365); err != nil {
return Only(ctx, errors.Wrap(err, "Failed to write repository configuration"))
}
return nil
}
@ -143,10 +149,12 @@ func connectS3Cmd(cmd *cobra.Command, args []string) error {
if err != nil {
return Only(ctx, err)
}
s3Cfg, err := s.S3Config()
if err != nil {
return Only(ctx, errors.Wrap(err, "Retrieving s3 configuration"))
}
m365, err := a.M365Config()
if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to parse m365 account config"))
@ -164,6 +172,7 @@ func connectS3Cmd(cmd *cobra.Command, args []string) error {
if err != nil {
return Only(ctx, errors.Wrap(err, "Failed to connect to the S3 repository"))
}
defer utils.CloseRepo(ctx, r)
Infof(ctx, "Connected to S3 bucket %s.", s3Cfg.Bucket)
@ -171,6 +180,7 @@ func connectS3Cmd(cmd *cobra.Command, args []string) error {
if err = config.WriteRepoConfig(ctx, s3Cfg, m365); err != nil {
return Only(ctx, errors.Wrap(err, "Failed to write repository configuration"))
}
return nil
}

View File

@ -25,6 +25,7 @@ func TestS3IntegrationSuite(t *testing.T) {
); err != nil {
t.Skip(err)
}
suite.Run(t, new(S3IntegrationSuite))
}
@ -45,6 +46,7 @@ func (suite *S3IntegrationSuite) TestInitS3Cmd() {
vpr, configFP, err := tester.MakeTempTestConfigClone(t, nil)
require.NoError(t, err)
ctx = config.SetViper(ctx, vpr)
cmd := tester.StubRootCmd(
@ -68,6 +70,7 @@ func (suite *S3IntegrationSuite) TestInitS3Cmd_missingBucket() {
vpr, configFP, err := tester.MakeTempTestConfigClone(t, nil)
require.NoError(t, err)
ctx = config.SetViper(ctx, vpr)
cmd := tester.StubRootCmd(
@ -95,6 +98,7 @@ func (suite *S3IntegrationSuite) TestConnectS3Cmd() {
}
vpr, configFP, err := tester.MakeTempTestConfigClone(t, force)
require.NoError(t, err)
ctx = config.SetViper(ctx, vpr)
// init the repo first
@ -123,6 +127,7 @@ func (suite *S3IntegrationSuite) TestConnectS3Cmd_BadBucket() {
vpr, configFP, err := tester.MakeTempTestConfigClone(t, nil)
require.NoError(t, err)
ctx = config.SetViper(ctx, vpr)
cmd := tester.StubRootCmd(
@ -146,6 +151,7 @@ func (suite *S3IntegrationSuite) TestConnectS3Cmd_BadPrefix() {
vpr, configFP, err := tester.MakeTempTestConfigClone(t, nil)
require.NoError(t, err)
ctx = config.SetViper(ctx, vpr)
cmd := tester.StubRootCmd(

View File

@ -21,6 +21,7 @@ func TestS3Suite(t *testing.T) {
func (suite *S3Suite) TestAddS3Commands() {
expectUse := s3ProviderCommand
table := []struct {
name string
use string

View File

@ -88,6 +88,7 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
// others
options.AddOperationFlags(c)
}
return c
}
@ -144,6 +145,7 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
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.NewExchangeRestore()
@ -177,6 +179,7 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
}
Infof(ctx, "Restored Exchange in %s for user %s.\n", s.Provider, user)
return nil
}
@ -210,6 +213,7 @@ func includeExchangeContacts(sel *selectors.ExchangeRestore, users, contactFolde
if len(contactFolders) == 0 {
return
}
if len(contacts) > 0 {
sel.Include(sel.Contacts(users, contactFolders, contacts))
} else {
@ -221,6 +225,7 @@ func includeExchangeEmails(sel *selectors.ExchangeRestore, users, emailFolders,
if len(emailFolders) == 0 {
return
}
if len(emails) > 0 {
sel.Include(sel.Mails(users, emailFolders, emails))
} else {
@ -232,6 +237,7 @@ func includeExchangeEvents(sel *selectors.ExchangeRestore, users, events []strin
if len(events) == 0 {
return
}
sel.Include(sel.Events(users, events))
}
@ -250,6 +256,7 @@ func filterExchangeInfoMailReceivedAfter(sel *selectors.ExchangeRestore, receive
if len(receivedAfter) == 0 {
return
}
sel.Filter(sel.MailReceivedAfter(receivedAfter))
}
@ -257,6 +264,7 @@ func filterExchangeInfoMailReceivedBefore(sel *selectors.ExchangeRestore, receiv
if len(receivedBefore) == 0 {
return
}
sel.Filter(sel.MailReceivedBefore(receivedBefore))
}
@ -264,6 +272,7 @@ func filterExchangeInfoMailSender(sel *selectors.ExchangeRestore, sender string)
if len(sender) == 0 {
return
}
sel.Filter(sel.MailSender([]string{sender}))
}
@ -271,6 +280,7 @@ func filterExchangeInfoMailSubject(sel *selectors.ExchangeRestore, subject strin
if len(subject) == 0 {
return
}
sel.Filter(sel.MailSubject([]string{subject}))
}
@ -282,24 +292,30 @@ func validateExchangeRestoreFlags(
if len(backupID) == 0 {
return errors.New("a backup ID is required")
}
lu := len(users)
lc, lcf := len(contacts), len(contactFolders)
le, lef := len(emails), len(emailFolders)
lev := len(events)
// if only the backupID is populated, that's the same as --all
if lu+lc+lcf+le+lef+lev == 0 {
return nil
}
if lu == 0 {
return errors.New("requires one or more --user ids, the wildcard --user *, or the --all flag")
}
if lc > 0 && lcf == 0 {
return errors.New(
"one or more --contact-folder ids or the wildcard --contact-folder * must be included to specify a --contact")
}
if le > 0 && lef == 0 {
return errors.New(
"one or more --email-folder ids or the wildcard --email-folder * must be included to specify a --email")
}
return nil
}

View File

@ -37,6 +37,7 @@ func TestRestoreExchangeIntegrationSuite(t *testing.T) {
); err != nil {
t.Skip(err)
}
suite.Run(t, new(RestoreExchangeIntegrationSuite))
}
@ -62,8 +63,8 @@ func (suite *RestoreExchangeIntegrationSuite) SetupSuite() {
}
suite.vpr, suite.cfgFP, err = tester.MakeTempTestConfigClone(t, force)
require.NoError(t, err)
ctx := config.SetViper(tester.NewContext(), suite.vpr)
ctx := config.SetViper(tester.NewContext(), suite.vpr)
suite.m365UserID = tester.M365UserID(t)
// init the repo first

View File

@ -23,6 +23,7 @@ func TestExchangeSuite(t *testing.T) {
func (suite *ExchangeSuite) TestAddExchangeCommands() {
expectUse := exchangeServiceCommand
table := []struct {
name string
use string
@ -52,6 +53,7 @@ func (suite *ExchangeSuite) TestAddExchangeCommands() {
func (suite *ExchangeSuite) TestValidateExchangeRestoreFlags() {
stub := []string{"id-stub"}
table := []struct {
name string
contacts, contactFolders, emails, emailFolders, events, users []string
@ -137,6 +139,7 @@ func (suite *ExchangeSuite) TestValidateExchangeRestoreFlags() {
func (suite *ExchangeSuite) TestIncludeExchangeRestoreDataSelectors() {
stub := []string{"id-stub"}
a := []string{utils.Wildcard}
table := []struct {
name string
contacts, contactFolders, emails, emailFolders, events, users []string
@ -319,6 +322,7 @@ func (suite *ExchangeSuite) TestIncludeExchangeRestoreDataSelectors() {
func (suite *ExchangeSuite) TestFilterExchangeRestoreInfoSelectors() {
stub := "id-stub"
a := utils.Wildcard
table := []struct {
name string
after, before, sender, subject string

View File

@ -23,6 +23,7 @@ func RequireProps(props map[string]string) error {
return errors.New(name + " is required to perform this command")
}
}
return nil
}
@ -43,6 +44,7 @@ func HasNoFlagsAndShownHelp(cmd *cobra.Command) bool {
cobra.CheckErr(cmd.Help())
return true
}
return false
}

View File

@ -34,6 +34,7 @@ func main() {
"cli-folder",
"./cmd/mdgen/cli_markdown",
"relative path to the folder where cli docs will be generated (default: ./cmd/mdgen/cli_markdown)")
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
@ -43,6 +44,7 @@ func genDocs(cmd *cobra.Command, args []string) {
if err := makeDir(cliMarkdownDir); err != nil {
fatal(errors.Wrap(err, "preparing directory for markdown generation"))
}
err := doc.GenMarkdownTree(cli.CorsoCommand(), cliMarkdownDir)
if err != nil {
fatal(errors.Wrap(err, "generating the Corso CLI markdown"))

View File

@ -42,6 +42,7 @@ func doFolderPurge(cmd *cobra.Command, args []string) error {
M365: credentials.GetM365(),
TenantID: common.First(tenant, os.Getenv(account.TenantID)),
}
acct, err := account.NewAccount(account.ProviderM365, m365Cfg)
if err != nil {
return Only(ctx, errors.Wrap(err, "finding m365 account details"))
@ -67,21 +68,26 @@ func doFolderPurge(cmd *cobra.Command, args []string) error {
return Only(ctx, errors.Wrap(err, "parsing before flag to time"))
}
}
stLen := len(common.SimpleDateTimeFormat)
// delete files
for _, mf := range mfs {
// compare the folder time to the deletion boundary time first
var del bool
dnLen := len(mf.DisplayName)
var (
del bool
dnLen = len(mf.DisplayName)
)
if dnLen > stLen {
dnSuff := mf.DisplayName[dnLen-stLen:]
dnTime, err := common.ParseTime(dnSuff)
if err != nil {
Info(ctx, errors.Wrapf(err, "Error: deleting folder [%s]", mf.DisplayName))
continue
}
del = dnTime.Before(beforeTime)
}
@ -90,6 +96,7 @@ func doFolderPurge(cmd *cobra.Command, args []string) error {
}
Info(ctx, "Deleting folder: ", mf.DisplayName)
err = exchange.DeleteMailFolder(gc.Service(), user, mf.ID)
if err != nil {
Info(ctx, errors.Wrapf(err, "Error: deleting folder [%s]", mf.DisplayName))