diff --git a/CHANGELOG.md b/CHANGELOG.md index 06f2fd11c..3cf04ba6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Handle calendar events with no body. - Items not being deleted if they were created and deleted during item enumeration of a OneDrive backup. - Enable compression for all data uploaded by kopia. +- SharePoint --folder selectors correctly return items. ## [v0.6.1] (beta) - 2023-03-21 @@ -33,8 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Known Issues - Owner (Full control) or empty (Restricted View) roles cannot be restored for OneDrive - OneDrive will not do an incremental backup if permissions are being backed up. - -### Known Issues +- SharePoint --folder selection in details and restore always return "no items match the specified selectors". - Event instance exceptions (ie: changes to a single event within a recurring series) are not backed up. ## [v0.5.0] (beta) - 2023-03-13 diff --git a/src/cli/backup/exchange.go b/src/cli/backup/exchange.go index cc2a36d64..87a1f2c56 100644 --- a/src/cli/backup/exchange.go +++ b/src/cli/backup/exchange.go @@ -342,6 +342,8 @@ func runDetailsExchangeCmd( return nil, errors.Wrap(errs.Failure(), "Failed to get backup details in the repository") } + ctx = clues.Add(ctx, "details_entries", len(d.Entries)) + if !skipReduce { sel := utils.IncludeExchangeRestoreDataSelectors(opts) utils.FilterExchangeRestoreInfoSelectors(sel, opts) diff --git a/src/cli/backup/onedrive.go b/src/cli/backup/onedrive.go index 490697e54..0210760fa 100644 --- a/src/cli/backup/onedrive.go +++ b/src/cli/backup/onedrive.go @@ -281,6 +281,8 @@ func runDetailsOneDriveCmd( return nil, errors.Wrap(errs.Failure(), "Failed to get backup details in the repository") } + ctx = clues.Add(ctx, "details_entries", len(d.Entries)) + if !skipReduce { sel := utils.IncludeOneDriveRestoreDataSelectors(opts) utils.FilterOneDriveRestoreInfoSelectors(sel, opts) diff --git a/src/cli/backup/sharepoint.go b/src/cli/backup/sharepoint.go index 19a2f0e81..07cc79b7d 100644 --- a/src/cli/backup/sharepoint.go +++ b/src/cli/backup/sharepoint.go @@ -389,6 +389,8 @@ func runDetailsSharePointCmd( return nil, errors.Wrap(errs.Failure(), "Failed to get backup details in the repository") } + ctx = clues.Add(ctx, "details_entries", len(d.Entries)) + if !skipReduce { sel := utils.IncludeSharePointRestoreDataSelectors(opts) utils.FilterSharePointRestoreInfoSelectors(sel, opts) diff --git a/src/internal/operations/restore.go b/src/internal/operations/restore.go index 705799fdd..b6e953f5b 100644 --- a/src/internal/operations/restore.go +++ b/src/internal/operations/restore.go @@ -196,6 +196,7 @@ func (op *RestoreOperation) do( ctx = clues.Add( ctx, "resource_owner", bup.Selector.DiscreteOwner, + "details_entries", len(deets.Entries), "details_paths", len(paths), "backup_snapshot_id", bup.SnapshotID, "backup_version", bup.Version) diff --git a/src/pkg/selectors/sharepoint.go b/src/pkg/selectors/sharepoint.go index d9b634bbb..328c49fed 100644 --- a/src/pkg/selectors/sharepoint.go +++ b/src/pkg/selectors/sharepoint.go @@ -503,8 +503,9 @@ func (c sharePointCategory) pathValues( ent details.DetailsEntry, ) (map[categorizer][]string, error) { var ( - folderCat, itemCat categorizer - itemName = repo.Item() + folderCat, itemCat categorizer + itemName = repo.Item() + dropDriveFolderPrefix bool ) switch c { @@ -513,6 +514,7 @@ func (c sharePointCategory) pathValues( return nil, clues.New("no SharePoint ItemInfo in details") } + dropDriveFolderPrefix = true folderCat, itemCat = SharePointLibraryFolder, SharePointLibraryItem itemName = ent.SharePoint.ItemName @@ -526,8 +528,14 @@ func (c sharePointCategory) pathValues( return nil, clues.New("unrecognized sharePointCategory").With("category", c) } + rFld := repo.Folder(false) + if dropDriveFolderPrefix { + // like onedrive, ignore `drives//root:` for library folder comparison + rFld = path.Builder{}.Append(repo.Folders()...).PopFront().PopFront().PopFront().String() + } + result := map[categorizer][]string{ - folderCat: {repo.Folder(false)}, + folderCat: {rFld}, itemCat: {itemName, ent.ShortRef}, } diff --git a/src/pkg/selectors/sharepoint_test.go b/src/pkg/selectors/sharepoint_test.go index 8624c40a1..bec730956 100644 --- a/src/pkg/selectors/sharepoint_test.go +++ b/src/pkg/selectors/sharepoint_test.go @@ -199,13 +199,14 @@ func (suite *SharePointSelectorSuite) TestToSharePointRestore() { func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { var ( - pairAC = "folderA/folderC" - pairGH = "folderG/folderH" - item = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", "folderA/folderB", "item") - item2 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", pairAC, "item2") - item3 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", "folderD/folderE", "item3") - item4 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item4") - item5 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item5") + drivePfx = "drive/drive!id/root:/" + pairAC = "folderA/folderC" + pairGH = "folderG/folderH" + item = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", drivePfx+"folderA/folderB", "item") + item2 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", drivePfx+pairAC, "item2") + item3 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", drivePfx+"folderD/folderE", "item3") + item4 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item4") + item5 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item5") ) deets := &details.Details{ @@ -327,26 +328,32 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { } func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() { - itemName := "item" - shortRef := "short" - elems := []string{"dir1", "dir2", itemName + "-id"} + var ( + itemName = "item" + shortRef = "short" + driveElems = []string{"drive", "drive!id", "root:", "dir1", "dir2", itemName + "-id"} + elems = []string{"dir1", "dir2", itemName + "-id"} + ) table := []struct { - name string - sc sharePointCategory - expected map[categorizer][]string + name string + sc sharePointCategory + pathElems []string + expected map[categorizer][]string }{ { - name: "SharePoint Libraries", - sc: SharePointLibraryItem, + name: "SharePoint Libraries", + sc: SharePointLibraryItem, + pathElems: driveElems, expected: map[categorizer][]string{ SharePointLibraryFolder: {"dir1/dir2"}, SharePointLibraryItem: {itemName, shortRef}, }, }, { - name: "SharePoint Lists", - sc: SharePointListItem, + name: "SharePoint Lists", + sc: SharePointListItem, + pathElems: elems, expected: map[categorizer][]string{ SharePointList: {"dir1/dir2"}, SharePointListItem: {"item-id", shortRef}, @@ -364,7 +371,7 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() { path.SharePointService, test.sc.PathType(), true, - elems...) + test.pathElems...) require.NoError(t, err, clues.ToCore(err)) ent := details.DetailsEntry{