Fix wsl errors in cmd and cli packages (#651)
This commit is contained in:
parent
f24ad6ccbd
commit
88a318a7c0
@ -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)
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ func m365ConfigsFromViper(vpr *viper.Viper) (account.M365Config, error) {
|
||||
}
|
||||
|
||||
m365.TenantID = vpr.GetString(TenantIDKey)
|
||||
|
||||
return m365, nil
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -190,6 +190,7 @@ func TestConfigIntegrationSuite(t *testing.T) {
|
||||
); err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
|
||||
suite.Run(t, new(ConfigIntegrationSuite))
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ func (suite *EnvSuite) TestAddEnvCommands() {
|
||||
cmd := &cobra.Command{Use: "root"}
|
||||
|
||||
AddCommands(cmd)
|
||||
|
||||
c := envCmd()
|
||||
require.NotNil(t, c)
|
||||
|
||||
|
||||
@ -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)))
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -21,6 +21,7 @@ func TestS3Suite(t *testing.T) {
|
||||
|
||||
func (suite *S3Suite) TestAddS3Commands() {
|
||||
expectUse := s3ProviderCommand
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
use string
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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"))
|
||||
|
||||
@ -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))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user