diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8b642a6..9e8aa9e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,7 +37,7 @@ jobs: continue-on-error: true - name: Run integration tests if: startsWith(github.ref, 'refs/tags/') - run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -scheme 'CryptomatorCloudAccessIntegrationTests' -destination "name=$DEVICE" -derivedDataPath $DERIVED_DATA_PATH test | xcpretty + run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -scheme 'CryptomatorCloudAccessIntegrationTests' -destination "name=$DEVICE" -derivedDataPath $DERIVED_DATA_PATH -retry-tests-on-failure test | xcpretty env: DROPBOX_ACCESS_TOKEN: ${{ secrets.DROPBOX_ACCESS_TOKEN }} GOOGLE_DRIVE_CLIENT_ID: ${{ secrets.GOOGLE_DRIVE_CLIENT_ID }} diff --git a/Sources/CryptomatorCloudAccess/GoogleDrive/GoogleDriveCloudProvider.swift b/Sources/CryptomatorCloudAccess/GoogleDrive/GoogleDriveCloudProvider.swift index 4444b71..9b78902 100644 --- a/Sources/CryptomatorCloudAccess/GoogleDrive/GoogleDriveCloudProvider.swift +++ b/Sources/CryptomatorCloudAccess/GoogleDrive/GoogleDriveCloudProvider.swift @@ -367,6 +367,7 @@ public class GoogleDriveCloudProvider: CloudProvider { let name = endCloudPath.pathComponents[i] currentPath = currentPath.appendingPathComponent(name) parentItem = try awaitPromise(self.getGoogleDriveItem(name: name, parentItem: parentItem)) + try self.identifierCache.addOrUpdate(parentItem) } fulfill(parentItem) } @@ -393,11 +394,8 @@ public class GoogleDriveCloudProvider: CloudProvider { CloudAccessDDLogDebug("GoogleDriveCloudProvider: getGoogleDriveItem(name: \(name), parentItem: \(parentItem.identifier)) received result: \((result as? GTLRObject)?.jsonString() ?? result)") if let fileList = result as? GTLRDrive_FileList { for file in fileList.files ?? [GTLRDrive_File]() where file.name == name { - let item = try GoogleDriveItem(cloudPath: parentItem.cloudPath.appendingPathComponent(name), file: file) - try self.identifierCache.addOrUpdate(item) - return item + return try GoogleDriveItem(cloudPath: parentItem.cloudPath.appendingPathComponent(name), file: file) } - try self.identifierCache.invalidate(parentItem) throw CloudProviderError.itemNotFound } else { throw GoogleDriveError.unexpectedResultType diff --git a/Sources/CryptomatorCloudAccess/LocalFileSystem/LocalFileSystemProvider.swift b/Sources/CryptomatorCloudAccess/LocalFileSystem/LocalFileSystemProvider.swift index 6440ed2..3dd7134 100644 --- a/Sources/CryptomatorCloudAccess/LocalFileSystem/LocalFileSystemProvider.swift +++ b/Sources/CryptomatorCloudAccess/LocalFileSystem/LocalFileSystemProvider.swift @@ -143,32 +143,33 @@ public class LocalFileSystemProvider: CloudProvider { } private func fillCacheAfterCheck(for cloudPath: CloudPath, url: URL, directoryEnumerator: FileManager.DirectoryEnumerator, promise: Promise) { - var cachedItemsCount: Int64 = 0 - for case let childURL as URL in directoryEnumerator { - autoreleasepool { - guard !childURL.isHidden || self.fileManager.isUbiquitousItem(at: childURL) else { - return - } - let iCloudCompatibleChildURL = url.appendingPathComponent(self.getItemName(forItemAt: childURL)) - guard iCloudCompatibleChildURL.lastPathComponent.prefix(1) != "." else { - return - } - do { - let childItemMetadata = try awaitPromise(self.getItemMetadata(forItemAt: iCloudCompatibleChildURL, parentCloudPath: cloudPath)) - cachedItemsCount += 1 - try self.cache.save(childItemMetadata, for: cloudPath, index: cachedItemsCount) - } catch CloudProviderError.itemNotFound { - // Ignore item that can't be found anyway, this should not prevent fetching item list - return - } catch { - CloudAccessDDLogDebug("LocalFileSystemProvider: fillCache(for: \(cloudPath.path)) failed with error: \(error)") - promise.reject(error) - return + do { + var cachedItemsCount: Int64 = 0 + for case let childURL as URL in directoryEnumerator { + try autoreleasepool { + guard !childURL.isHidden || self.fileManager.isUbiquitousItem(at: childURL) else { + return + } + let iCloudCompatibleChildURL = url.appendingPathComponent(self.getItemName(forItemAt: childURL)) + guard iCloudCompatibleChildURL.lastPathComponent.prefix(1) != "." else { + return + } + do { + let childItemMetadata = try awaitPromise(self.getItemMetadata(forItemAt: iCloudCompatibleChildURL, parentCloudPath: cloudPath)) + cachedItemsCount += 1 + try self.cache.save(childItemMetadata, for: cloudPath, index: cachedItemsCount) + } catch CloudProviderError.itemNotFound { + // Ignore item that can't be found anyway, this should not prevent fetching item list + return + } } } + CloudAccessDDLogDebug("LocalFileSystemProvider: fillCache(for: \(cloudPath.path)) finished") + promise.fulfill(()) + } catch { + CloudAccessDDLogDebug("LocalFileSystemProvider: fillCache(for: \(cloudPath.path)) failed with error: \(error)") + promise.reject(error) } - CloudAccessDDLogDebug("LocalFileSystemProvider: fillCache(for: \(cloudPath.path)) finished") - promise.fulfill(()) } private func getCachedElements(for cloudPath: CloudPath, pageToken: String?) -> Promise { diff --git a/Sources/CryptomatorCloudAccess/OneDrive/OneDriveCloudProvider.swift b/Sources/CryptomatorCloudAccess/OneDrive/OneDriveCloudProvider.swift index 2b3cc1f..2398948 100644 --- a/Sources/CryptomatorCloudAccess/OneDrive/OneDriveCloudProvider.swift +++ b/Sources/CryptomatorCloudAccess/OneDrive/OneDriveCloudProvider.swift @@ -545,6 +545,7 @@ public class OneDriveCloudProvider: CloudProvider { let itemName = endCloudPath.pathComponents[i] currentPath = currentPath.appendingPathComponent(itemName) parentItem = try awaitPromise(self.getOneDriveItem(for: itemName, withParentItem: parentItem)) + try self.identifierCache.addOrUpdate(parentItem) } fulfill(parentItem) } @@ -557,14 +558,7 @@ public class OneDriveCloudProvider: CloudProvider { let request = NSMutableURLRequest(url: url) return executeMSURLSessionDataTaskWithErrorMapping(with: request).then { data -> OneDriveItem in let driveItem = try MSGraphDriveItem(data: data) - let item = OneDriveItem(cloudPath: parentItem.cloudPath.appendingPathComponent(name), driveItem: driveItem) - try self.identifierCache.addOrUpdate(item) - return item - }.recover { error -> OneDriveItem in - if case CloudProviderError.itemNotFound = error { - try self.identifierCache.invalidate(parentItem) - } - throw error + return OneDriveItem(cloudPath: parentItem.cloudPath.appendingPathComponent(name), driveItem: driveItem) } } diff --git a/Sources/CryptomatorCloudAccess/PCloud/PCloudCloudProvider.swift b/Sources/CryptomatorCloudAccess/PCloud/PCloudCloudProvider.swift index 54ab881..51eb499 100644 --- a/Sources/CryptomatorCloudAccess/PCloud/PCloudCloudProvider.swift +++ b/Sources/CryptomatorCloudAccess/PCloud/PCloudCloudProvider.swift @@ -427,6 +427,7 @@ public class PCloudCloudProvider: CloudProvider { let itemName = endCloudPath.pathComponents[i] currentPath = currentPath.appendingPathComponent(itemName) parentItem = try awaitPromise(self.getPCloudItem(for: itemName, withParentItem: parentItem)) + try self.identifierCache.addOrUpdate(parentItem) } fulfill(parentItem) } @@ -439,16 +440,13 @@ public class PCloudCloudProvider: CloudProvider { guard let content = metadata.contents.first(where: { $0.fileMetadata?.name == name || $0.folderMetadata?.name == name }) else { throw CloudProviderError.itemNotFound } - let item = try PCloudItem(cloudPath: parentItem.cloudPath.appendingPathComponent(name), content: content) - try self.identifierCache.addOrUpdate(item) - return item + return try PCloudItem(cloudPath: parentItem.cloudPath.appendingPathComponent(name), content: content) }.recover { error -> PCloudItem in CloudAccessDDLogDebug("PCloudCloudProvider: getPCloudItem(for: \(name), withParentItem: \(parentItem.identifier)) failed with error: \(error)") guard let error = error as? CallError else { throw error } if case CallError.methodError(.folderDoesNotExist) = error { - try self.identifierCache.invalidate(parentItem) throw CloudProviderError.itemNotFound } else { throw error