Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Google Drive Preset #2921 #3270

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

siard-y
Copy link

@siard-y siard-y commented Jan 2, 2024

This pull request addresses issue #2921, my first open-source contribution.

When creating a vault on MacOS, the code will now look through ~/Library/GoogleCloud/GoogleDrive-*/* if it exists. Otherwise it will use the fallback options, which remain in the code.

Here is a quick example of how it looks in the UI for now:
image

closes #2921

Summary by CodeRabbit

  • New Features

    • Introduced location presets for Google Drive on macOS and Windows, enhancing the integration with these platforms.
  • Refactor

    • Renamed and updated classes to better reflect their purpose for specific operating systems.
  • Documentation

    • Updated module information to include new location presets providers.

@CLAassistant
Copy link

CLAassistant commented Jan 2, 2024

CLA assistant check
All committers have signed the CLA.

Copy link

coderabbitai bot commented Jan 2, 2024

Walkthrough

The project has been updated to enhance the Google Drive location presets, particularly focusing on macOS and Windows platforms. The changes include dynamic path detection for various locales and account configurations, as well as a potential UI refactor to handle a more extensive list of cloud locations. This addresses the need for better Google Drive integration across different user setups.

Changes

File Change Summary
src/main/java/module-info.java Added platform-specific LocationPresetsProvider for Google Drive.
.../common/locationpresets/GoogleDriveMacLocationPresetsProvider.java Introduced class for macOS Google Drive location presets.
.../common/locationpresets/GoogleDriveWindowsLocationPresetsProvider.java Renamed class to specify Windows and removed @OperatingSystem(MAC) annotation.

Assessment against linked issues

Objective Addressed Explanation
Auto-detect Google Drive accounts and drives (#2921)
Dynamically detect path for Google Drive on non-English locales and multiple accounts/drives (#2921)
Refactor UI for longer display names and cloud list (#2921) The summary mentions potential UI refactoring, but without details on the implementation, it's unclear if this is fully addressed.

Poem

As the moon doth rise and the night is nigh,
A rabbit hops through the code, so spry.
With each keystroke, a fix takes flight,
For clouds and drives to sync just right. 🌕🐇💻

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • You can directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • You can tag CodeRabbit on specific lines of code or entire files in the PR by tagging @coderabbitai in a comment. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • You can tag @coderabbitai in a PR comment and ask questions about the PR and the codebase. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid.
    • @coderabbitai read the files in the src/scheduler package and generate README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

coderabbitai[bot]

This comment was marked as outdated.

- The code now defaults to searching through '~/Library/CloudStorage/GoogleDrive-*/*' before using the fallback options.
…2921

- Change imports accordingly in module-info.java
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 6

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 325092e and d85c6c8.
Files selected for processing (3)
  • src/main/java/module-info.java (2 hunks)
  • src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java (1 hunks)
  • src/main/java/org/cryptomator/common/locationpresets/GoogleDriveWindowsLocationPresetsProvider.java (2 hunks)
Files skipped from review as they are similar to previous changes (2)
  • src/main/java/module-info.java
  • src/main/java/org/cryptomator/common/locationpresets/GoogleDriveWindowsLocationPresetsProvider.java
Additional comments: 3
src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java (3)
  • 22-22: The PATTERN predicate is correctly defined to match directory names starting with "GoogleDrive-".

  • 32-40: The logic in getLocations method correctly checks for the presence of Google Drive locations and handles fallbacks. Ensure that the isLocationPresent method correctly resolves the LOCATION path.

  • 43-44: The isPresent method correctly combines the check for the standard location and the fallback locations.

Comment on lines +47 to +52
public static boolean isLocationPresent() {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(LOCATION, "GoogleDrive-*")) {
return stream.iterator().hasNext();
} catch (IOException e) {
return false;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider catching UncheckedIOException in isLocationPresent to handle potential runtime exceptions from the stream operations.

try (DirectoryStream<Path> stream = Files.newDirectoryStream(LOCATION, "GoogleDrive-*")) {
  return stream.iterator().hasNext();
} catch (IOException e) {
  return false;
+ } catch (UncheckedIOException e) {
+   return false;
}

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
public static boolean isLocationPresent() {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(LOCATION, "GoogleDrive-*")) {
return stream.iterator().hasNext();
} catch (IOException e) {
return false;
}
public static boolean isLocationPresent() {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(LOCATION, "GoogleDrive-*")) {
return stream.iterator().hasNext();
} catch (IOException e) {
return false;
} catch (UncheckedIOException e) {
return false;
}

Comment on lines +75 to +91
private Stream<LocationPreset> getCloudStorageDirLocations() {
try (var dirStream = Files.list(LOCATION)) {
var presets = dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString()))
.flatMap(accountPath -> {
try {
return Files.list(accountPath)
.filter(Files::isDirectory)
.map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath));
} catch (IOException e) {
throw new RuntimeException(e);
}
}).toList();
return presets.stream();
}
catch (IOException | UncheckedIOException e) {
return Stream.of();
}
Copy link

@coderabbitai coderabbitai bot Jan 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refine the exception handling in getCloudStorageDirLocations to avoid throwing RuntimeException. Consider logging the exception and returning an empty stream instead.

try (var dirStream = Files.list(LOCATION)) {
  // ... existing code ...
} catch (IOException e) {
-   throw new RuntimeException(e);
+   // Log the exception and handle it appropriately
+   return Stream.empty();
}

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
private Stream<LocationPreset> getCloudStorageDirLocations() {
try (var dirStream = Files.list(LOCATION)) {
var presets = dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString()))
.flatMap(accountPath -> {
try {
return Files.list(accountPath)
.filter(Files::isDirectory)
.map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath));
} catch (IOException e) {
throw new RuntimeException(e);
}
}).toList();
return presets.stream();
}
catch (IOException | UncheckedIOException e) {
return Stream.of();
}
private Stream<LocationPreset> getCloudStorageDirLocations() {
try (var dirStream = Files.list(LOCATION)) {
var presets = dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString()))
.flatMap(accountPath -> {
try {
return Files.list(accountPath)
.filter(Files::isDirectory)
.map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath));
} catch (IOException e) {
throw new RuntimeException(e);
}
}).toList();
return presets.stream();
}
catch (IOException | UncheckedIOException e) {
// Log the exception and handle it appropriately
return Stream.empty();
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or throw a new UncheckedIOException(e), which will also result in an empty stream due to the outer catch block.

The suggestion by @coderabbitai has the advantage to only skip the accountPath in which the exception occurred, retaining other results.

Regardless, I would suggest to move the code from within the flatMap to a new private function for increased readability.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@overheadhunter Throwing a new UncheckedIOException(e) is indeed a valid alternative, and I concur that refactoring the code within the flatMap into a private method would enhance readability. Here's how it could look:

private Stream<LocationPreset> getCloudStorageDirLocations() {
    try (var dirStream = Files.list(LOCATION)) {
        return dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString()))
                .flatMap(this::getPresetsFromAccountPath)
                .toList().stream();
    } catch (IOException | UncheckedIOException e) {
        // Log the exception and handle it appropriately
        return Stream.empty();
    }
}

private Stream<LocationPreset> getPresetsFromAccountPath(Path accountPath) {
    try {
        return Files.list(accountPath)
                .filter(Files::isDirectory)
                .map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath));
    } catch (IOException e) {
        // Log the exception and handle it appropriately
        return Stream.empty();
    }
}

This separates the concerns and makes the stream operations more manageable.

@JaniruTEC
Copy link
Contributor

Hey @siard-y,
thank you for your contribution.
I haven't had time to review your PR properly yet, so please take any of the bots' opinions with a grain of salt
Also please keep in mind that force-pushing makes it harder for us to properly follow the change history.

Thank you for your patience!
~ JaniruTEC

Copy link
Contributor

@JaniruTEC JaniruTEC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again: Thank you very much for your contribution! None of my notes are major issues, but should be addressed regardless.

A few notes in general:

Maybe @infeo can continue from here on.


@OperatingSystem(MAC)
public final class GoogleDriveMacLocationPresetsProvider implements LocationPresetsProvider {
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a big fan of the name LOCATION since it's actually the parent, maybe think of something like ROOT_LOCATION.

return isLocationPresent() || FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory);
}

public static boolean isLocationPresent() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, not a fan of this name.

Comment on lines +76 to +77
try (var dirStream = Files.list(LOCATION)) {
var presets = dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString()))
Copy link
Contributor

@JaniruTEC JaniruTEC Jan 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Files#newDirectoryStream might be a better choice here as well.


public static boolean isLocationPresent() {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(LOCATION, "GoogleDrive-*")) {
return stream.iterator().hasNext();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please filter for directories.

Copy link
Member

@infeo infeo Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or directly use stream.anyMatch(Files::isDirectory) my bad, this is no regular stream.
My suggestion:

StreamSupport.stream(stream.spliterator(), false).anyMatch(Files::isDirectory)

Comment on lines +35 to +38
} else if(FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory)) {
return getFallbackLocation();
} else {
return Stream.of();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified. getFallbackLocation will return an empty stream if nothing matches.

.filter(Files::isDirectory)
.map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath));
} catch (IOException e) {
throw new RuntimeException(e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should behave the same way as the outer catch.

@JaniruTEC JaniruTEC requested a review from infeo January 5, 2024 19:05
@infeo
Copy link
Member

infeo commented Jan 8, 2024

I am not sure if there is always a drive dir or if it's possible for the account dir to already contain the cloud content.

Good question. @tobihagemann do you have any insights on Google Drive behaviour?

This PR duplicates a few things, especially the fallback paths.

Also here, we need some Google Drive on macOS knowledge.

This PR does not use com.google.drivefs.plist;

The current approach seems sufficient and robust to me. Adding more to it would require handling of failed file reading. An then still, we could fail because the directory is not readable. I would skip this for now.

Finally we need to keep the dialog size in mind.

Also thought about that, but need to test what happens on an overflow. (e.g. where are the ellipsis placed)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve Google Drive Preset
5 participants