diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator+SyncEngine.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator+SyncEngine.swift index 0fed8a9a7..f9e0ab0c7 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator+SyncEngine.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator+SyncEngine.swift @@ -196,16 +196,22 @@ extension FileProviderEnumerator { dispatchGroup.wait() guard criticalError == nil else { + Logger.enumeration.error( + "Received critical error stopping further scanning: \(criticalError!.errorDescription, privacy: .public)" + ) return ([], [], [], [], error: criticalError) } var childDirectoriesToScan: [NextcloudItemMetadataTable] = [] - var candidateMetadatas: [NextcloudItemMetadataTable] = - if scanChangesOnly { - allUpdatedMetadatas + allNewMetadatas - } else { - allMetadatas - } + var candidateMetadatas: [NextcloudItemMetadataTable] + + if scanChangesOnly, fastEnumeration { + candidateMetadatas = allUpdatedMetadatas + } else if scanChangesOnly { + candidateMetadatas = allUpdatedMetadatas + allNewMetadatas + } else { + candidateMetadatas = allMetadatas + } for candidateMetadata in candidateMetadatas { if candidateMetadata.directory { @@ -213,6 +219,8 @@ extension FileProviderEnumerator { } } + Logger.enumeration.debug("Candidate metadatas for further scan: \(candidateMetadatas, privacy: .public)") + if childDirectoriesToScan.isEmpty { return ( metadatas: allMetadatas, newMetadatas: allNewMetadatas, @@ -221,11 +229,12 @@ extension FileProviderEnumerator { } for childDirectory in childDirectoriesToScan { + Logger.enumeration.debug( + "About to recursively scan: \(childDirectory.urlBase, privacy: .public) with etag: \(childDirectory.etag, privacy: .public)" + ) let childScanResult = scanRecursively( - childDirectory, - ncAccount: ncAccount, - ncKit: ncKit, - scanChangesOnly: scanChangesOnly) + childDirectory, ncAccount: ncAccount, ncKit: ncKit, scanChangesOnly: scanChangesOnly + ) allMetadatas += childScanResult.metadatas allNewMetadatas += childScanResult.newMetadatas diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift index dc6e30621..e74011e8f 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift @@ -28,21 +28,24 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { private static let maxItemsPerFileProviderPage = 100 let ncAccount: NextcloudAccount let ncKit: NextcloudKit + let fastEnumeration: Bool var serverUrl: String = "" var isInvalidated = false private static func isSystemIdentifier(_ identifier: NSFileProviderItemIdentifier) -> Bool { identifier == .rootContainer || identifier == .trashContainer || identifier == .workingSet } - + init( enumeratedItemIdentifier: NSFileProviderItemIdentifier, ncAccount: NextcloudAccount, - ncKit: NextcloudKit + ncKit: NextcloudKit, + fastEnumeration: Bool = true ) { self.enumeratedItemIdentifier = enumeratedItemIdentifier self.ncAccount = ncAccount self.ncKit = ncKit + self.fastEnumeration = fastEnumeration if FileProviderEnumerator.isSystemIdentifier(enumeratedItemIdentifier) { Logger.enumeration.debug( diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift index 3bf161342..8a0d41fdf 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift @@ -51,6 +51,19 @@ import OSLog return session }() + // Whether or not we are going to recursively scan new folders when they are discovered. + // Apple's recommendation is that we should always scan the file hierarchy fully. + // This does lead to long load times when a file provider domain is initially configured. + // We can instead do a fast enumeration where we only scan folders as the user navigates through + // them, thereby avoiding this issue; the trade-off is that we will be unable to detect + // materialised file moves to unexplored folders, therefore deleting the item when we could have + // just moved it instead. + // + // Since it's not desirable to cancel a long recursive enumeration half-way through, we do the + // fast enumeration by default. We prompt the user on the client side to run a proper, full + // enumeration if they want for safety. + var fastEnumeration = true + required init(domain: NSFileProviderDomain) { // The containing application must create a domain using // `NSFileProviderManager.add(_:, completionHandler:)`. The system will then launch the @@ -787,7 +800,11 @@ import OSLog } return FileProviderEnumerator( - enumeratedItemIdentifier: containerItemIdentifier, ncAccount: ncAccount, ncKit: ncKit) + enumeratedItemIdentifier: containerItemIdentifier, + ncAccount: ncAccount, + ncKit: ncKit, + fastEnumeration: fastEnumeration + ) } func materializedItemsDidChange(completionHandler: @escaping () -> Void) {