Don't display folders in restore output (#3414)
#### Does this PR need a docs update or release note? - [x] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [ ] ⛔ No #### Type of change - [ ] 🌻 Feature - [x] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Supportability/Tests - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup #### Issue(s) * closes #3281 #### Test Plan - [x] 💪 Manual - [ ] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
ecb1fdc40a
commit
04a30ac662
@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Refined oneDrive rate limiter controls to reduce throttling errors.
|
||||
- Fix handling of duplicate folders at the same hierarchy level in Exchange. Duplicate folders will be merged during restore operations.
|
||||
- Fix backup for mailboxes that has used up all their storage quota
|
||||
- Restored folders no longer appear in the Restore results. Only restored items will be displayed.
|
||||
|
||||
### Known Issues
|
||||
- Restore operations will merge duplicate Exchange folders at the same hierarchy level into a single folder.
|
||||
|
||||
@ -116,7 +116,7 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
|
||||
return Only(ctx, clues.Wrap(err, "Failed to run Exchange restore"))
|
||||
}
|
||||
|
||||
ds.PrintEntries(ctx)
|
||||
ds.Items().PrintEntries(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ func restoreOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||
return Only(ctx, clues.Wrap(err, "Failed to run OneDrive restore"))
|
||||
}
|
||||
|
||||
ds.PrintEntries(ctx)
|
||||
ds.Items().PrintEntries(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ func restoreSharePointCmd(cmd *cobra.Command, args []string) error {
|
||||
return Only(ctx, clues.Wrap(err, "Failed to run SharePoint restore"))
|
||||
}
|
||||
|
||||
ds.PrintEntries(ctx)
|
||||
ds.Items().PrintEntries(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -139,25 +139,36 @@ type DetailsModel struct {
|
||||
// Print writes the DetailModel Entries to StdOut, in the format
|
||||
// requested by the caller.
|
||||
func (dm DetailsModel) PrintEntries(ctx context.Context) {
|
||||
printEntries(ctx, dm.Entries)
|
||||
}
|
||||
|
||||
type infoer interface {
|
||||
Entry | *Entry
|
||||
// Need this here so we can access the infoType function without a type
|
||||
// assertion. See https://stackoverflow.com/a/71378366 for more details.
|
||||
infoType() ItemType
|
||||
}
|
||||
|
||||
func printEntries[T infoer](ctx context.Context, entries []T) {
|
||||
if print.DisplayJSONFormat() {
|
||||
printJSON(ctx, dm)
|
||||
printJSON(ctx, entries)
|
||||
} else {
|
||||
printTable(ctx, dm)
|
||||
printTable(ctx, entries)
|
||||
}
|
||||
}
|
||||
|
||||
func printTable(ctx context.Context, dm DetailsModel) {
|
||||
func printTable[T infoer](ctx context.Context, entries []T) {
|
||||
perType := map[ItemType][]print.Printable{}
|
||||
|
||||
for _, de := range dm.Entries {
|
||||
it := de.infoType()
|
||||
for _, ent := range entries {
|
||||
it := ent.infoType()
|
||||
ps, ok := perType[it]
|
||||
|
||||
if !ok {
|
||||
ps = []print.Printable{}
|
||||
}
|
||||
|
||||
perType[it] = append(ps, print.Printable(de))
|
||||
perType[it] = append(ps, print.Printable(ent))
|
||||
}
|
||||
|
||||
for _, ps := range perType {
|
||||
@ -165,10 +176,10 @@ func printTable(ctx context.Context, dm DetailsModel) {
|
||||
}
|
||||
}
|
||||
|
||||
func printJSON(ctx context.Context, dm DetailsModel) {
|
||||
func printJSON[T infoer](ctx context.Context, entries []T) {
|
||||
ents := []print.Printable{}
|
||||
|
||||
for _, ent := range dm.Entries {
|
||||
for _, ent := range entries {
|
||||
ents = append(ents, print.Printable(ent))
|
||||
}
|
||||
|
||||
@ -194,7 +205,7 @@ func (dm DetailsModel) Paths() []string {
|
||||
// Items returns a slice of *ItemInfo that does not contain any FolderInfo
|
||||
// entries. Required because not all folders in the details are valid resource
|
||||
// paths, and we want to slice out metadata.
|
||||
func (dm DetailsModel) Items() []*Entry {
|
||||
func (dm DetailsModel) Items() entrySet {
|
||||
res := make([]*Entry, 0, len(dm.Entries))
|
||||
|
||||
for i := 0; i < len(dm.Entries); i++ {
|
||||
@ -457,6 +468,13 @@ func withoutMetadataSuffix(id string) string {
|
||||
// Entry
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// Add a new type so we can transparently use PrintAll in different situations.
|
||||
type entrySet []*Entry
|
||||
|
||||
func (ents entrySet) PrintEntries(ctx context.Context) {
|
||||
printEntries(ctx, ents)
|
||||
}
|
||||
|
||||
// Entry describes a single item stored in a Backup
|
||||
type Entry struct {
|
||||
// RepoRef is the full storage path of the item in Kopia
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user