From 17057e8f8dfaf2e1521cc57d8635d4cf2398e7f1 Mon Sep 17 00:00:00 2001 From: Siard Date: Tue, 2 Jan 2024 10:11:48 +0100 Subject: [PATCH 01/12] Add Google Drive presets improvement. cryptomator/2921 - The code now defaults to searching through '~/Library/CloudStorage/GoogleDrive-*/*' before using the fallback options. --- .../GoogleDriveLocationPresetsProvider.java | 94 ++++++++++++++++--- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveLocationPresetsProvider.java index 970bea042..921201575 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveLocationPresetsProvider.java @@ -3,39 +3,105 @@ package org.cryptomator.common.locationpresets; import org.cryptomator.integrations.common.CheckAvailability; import org.cryptomator.integrations.common.OperatingSystem; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; +import java.util.regex.Pattern; import java.util.stream.Stream; import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC; -import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS; -@OperatingSystem(WINDOWS) @OperatingSystem(MAC) -@CheckAvailability public final class GoogleDriveLocationPresetsProvider implements LocationPresetsProvider { + private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath(); + private static final Predicate PATTERN = Pattern.compile("^GoogleDrive-[^/]+$").asMatchPredicate(); - private static final List LOCATIONS = Arrays.asList( // + private static final List FALLBACK_LOCATIONS = Arrays.asList( // LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive"), // LocationPresetsProvider.resolveLocation("~/Google Drive/My Drive"), // LocationPresetsProvider.resolveLocation("~/GoogleDrive"), // LocationPresetsProvider.resolveLocation("~/Google Drive") // ); - @CheckAvailability - public static boolean isPresent() { - return LOCATIONS.stream().anyMatch(Files::isDirectory); - } - @Override public Stream getLocations() { - return LOCATIONS.stream() // - .filter(Files::isDirectory) // - .map(location -> new LocationPreset("Google Drive", location)) // - .findFirst() // - .stream(); + if(isLocationPresent()) { + return getCloudStorageDirLocations(); + } else if(FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory)) { + return getFallbackLocation(); + } else { + return Stream.of(); + } } + @CheckAvailability + public static boolean isPresent() { + return isLocationPresent() || FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory); + } + + public static boolean isLocationPresent() { + try (DirectoryStream stream = Files.newDirectoryStream(LOCATION, "GoogleDrive-*")) { + return stream.iterator().hasNext(); + } catch (IOException e) { + return false; + } + } + + /** + * Returns Google Drive preset String. + * + * @param accountPath The path to the Google Drive account directory (e.g. {@code ~/Library/CloudStorage/GoogleDrive-username}) + * @param drivePath The path to the Google Drive file directory, within the account directory. (e.g. {@code ~/Library/CloudStorage/GoogleDrive-username/drive_name}) + * @return {@code String}. For example: "Google Drive - username - drive_name" + */ + private String getDriveLocationString(Path accountPath, Path drivePath) { + String accountName = accountPath.getFileName().toString().replace("GoogleDrive-", ""); + String driveName = drivePath.getFileName().toString(); + + return STR."Google Drive - \{accountName} - \{driveName}"; + } + + /** + * Handles searching through {@code ~/Library/CloudStorage/} for directories with the "{@code GoogleDrive-*}" pattern, + * and returns the corresponding presets. + * + * @return {@code Stream}. Displays as "{@code Google Drive - username - drive_name}" + */ + private Stream 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(); + } + } + + /** + * Uses {@code FALLBACK_LOCATIONS} for directories as fallback, if {@code ~/Library/CloudStorage/} isn't present. + * Returns the corresponding presets. + * + * @return {@code Stream}. Displays as "{@code Google Drive}" + */ + private Stream getFallbackLocation() { + return FALLBACK_LOCATIONS.stream() // + .filter(Files::isDirectory) // + .map(location -> new LocationPreset("Google Drive", location)) + .findFirst() + .stream(); + } } From d85c6c8f41ebbc3ed861dcc43c9203830bba1697 Mon Sep 17 00:00:00 2001 From: Siard Date: Tue, 2 Jan 2024 10:20:18 +0100 Subject: [PATCH 02/12] Create separate files for GoogleDrive presets providers. cryptomator/2921 - Change imports accordingly in module-info.java --- src/main/java/module-info.java | 5 ++- ...oogleDriveMacLocationPresetsProvider.java} | 2 +- ...leDriveWindowsLocationPresetsProvider.java | 38 +++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) rename src/main/java/org/cryptomator/common/locationpresets/{GoogleDriveLocationPresetsProvider.java => GoogleDriveMacLocationPresetsProvider.java} (97%) create mode 100644 src/main/java/org/cryptomator/common/locationpresets/GoogleDriveWindowsLocationPresetsProvider.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index b353b7a8a..bf318ab80 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -2,7 +2,8 @@ import ch.qos.logback.classic.spi.Configurator; import org.cryptomator.common.locationpresets.DropboxLinuxLocationPresetsProvider; import org.cryptomator.common.locationpresets.DropboxMacLocationPresetsProvider; import org.cryptomator.common.locationpresets.DropboxWindowsLocationPresetsProvider; -import org.cryptomator.common.locationpresets.GoogleDriveLocationPresetsProvider; +import org.cryptomator.common.locationpresets.GoogleDriveMacLocationPresetsProvider; +import org.cryptomator.common.locationpresets.GoogleDriveWindowsLocationPresetsProvider; import org.cryptomator.common.locationpresets.ICloudMacLocationPresetsProvider; import org.cryptomator.common.locationpresets.ICloudWindowsLocationPresetsProvider; import org.cryptomator.common.locationpresets.LeitzcloudLocationPresetsProvider; @@ -56,7 +57,7 @@ open module org.cryptomator.desktop { provides Configurator with LogbackConfiguratorFactory; provides LocationPresetsProvider with // DropboxWindowsLocationPresetsProvider, DropboxMacLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, // - GoogleDriveLocationPresetsProvider, // + GoogleDriveMacLocationPresetsProvider, GoogleDriveWindowsLocationPresetsProvider, // ICloudWindowsLocationPresetsProvider, ICloudMacLocationPresetsProvider, // LeitzcloudLocationPresetsProvider, // MegaLocationPresetsProvider, // diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java similarity index 97% rename from src/main/java/org/cryptomator/common/locationpresets/GoogleDriveLocationPresetsProvider.java rename to src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index 921201575..8aa32b91c 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -17,7 +17,7 @@ import java.util.stream.Stream; import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC; @OperatingSystem(MAC) -public final class GoogleDriveLocationPresetsProvider implements LocationPresetsProvider { +public final class GoogleDriveMacLocationPresetsProvider implements LocationPresetsProvider { private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath(); private static final Predicate PATTERN = Pattern.compile("^GoogleDrive-[^/]+$").asMatchPredicate(); diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveWindowsLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveWindowsLocationPresetsProvider.java new file mode 100644 index 000000000..fea1632c4 --- /dev/null +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveWindowsLocationPresetsProvider.java @@ -0,0 +1,38 @@ +package org.cryptomator.common.locationpresets; + +import org.cryptomator.integrations.common.CheckAvailability; +import org.cryptomator.integrations.common.OperatingSystem; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS; + +@OperatingSystem(WINDOWS) +@CheckAvailability +public final class GoogleDriveWindowsLocationPresetsProvider implements LocationPresetsProvider { + + private static final List LOCATIONS = Arrays.asList( // + LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive"), // + LocationPresetsProvider.resolveLocation("~/Google Drive/My Drive"), // + LocationPresetsProvider.resolveLocation("~/GoogleDrive"), // + LocationPresetsProvider.resolveLocation("~/Google Drive") // + ); + + @CheckAvailability + public static boolean isPresent() { + return LOCATIONS.stream().anyMatch(Files::isDirectory); + } + + @Override + public Stream getLocations() { + return LOCATIONS.stream() // + .filter(Files::isDirectory) // + .map(location -> new LocationPreset("Google Drive", location)) // + .findFirst() // + .stream(); + } +} From 8fb95b67d9b594081188a76f682d9add086514b7 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Wed, 4 Sep 2024 14:28:42 +0200 Subject: [PATCH 03/12] changes mentioned in pull #3270 --- ...GoogleDriveMacLocationPresetsProvider.java | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index 8aa32b91c..ead1f86a0 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -13,12 +13,13 @@ import java.util.List; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC; @OperatingSystem(MAC) public final class GoogleDriveMacLocationPresetsProvider implements LocationPresetsProvider { - private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath(); + private static final Path ROOT_LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath(); private static final Predicate PATTERN = Pattern.compile("^GoogleDrive-[^/]+$").asMatchPredicate(); private static final List FALLBACK_LOCATIONS = Arrays.asList( // @@ -30,24 +31,22 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres @Override public Stream getLocations() { - if(isLocationPresent()) { + if(isRootLocationPresent()) { return getCloudStorageDirLocations(); - } else if(FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory)) { - return getFallbackLocation(); } else { - return Stream.of(); + return getFallbackLocation(); } } @CheckAvailability public static boolean isPresent() { - return isLocationPresent() || FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory); + return isRootLocationPresent() || FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory); } - public static boolean isLocationPresent() { - try (DirectoryStream stream = Files.newDirectoryStream(LOCATION, "GoogleDrive-*")) { - return stream.iterator().hasNext(); - } catch (IOException e) { + public static boolean isRootLocationPresent() { + try (DirectoryStream stream = Files.newDirectoryStream(ROOT_LOCATION, "GoogleDrive-*")) { + return StreamSupport.stream(stream.spliterator(), false).anyMatch(Files::isDirectory); + } catch (IOException | UncheckedIOException e) { return false; } } @@ -66,28 +65,23 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres return STR."Google Drive - \{accountName} - \{driveName}"; } - /** - * Handles searching through {@code ~/Library/CloudStorage/} for directories with the "{@code GoogleDrive-*}" pattern, - * and returns the corresponding presets. - * - * @return {@code Stream}. Displays as "{@code Google Drive - username - drive_name}" - */ private Stream 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(); + try (var dirStream = Files.list(ROOT_LOCATION)) { + return dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString())) + .flatMap(this::getPresetsFromAccountPath) + .toList().stream(); + } catch (IOException | UncheckedIOException e) { + return Stream.empty(); } - catch (IOException | UncheckedIOException e) { - return Stream.of(); + } + + private Stream getPresetsFromAccountPath(Path accountPath) { + try (var driveStream = Files.newDirectoryStream(accountPath, Files::isDirectory)) { + List directories = StreamSupport.stream(driveStream.spliterator(), false).toList(); + return directories.stream() + .map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath)); + } catch (IOException e) { + return Stream.empty(); } } From 1946fc6c0ed3447579c3c6db4dd804bfe7e4558b Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Wed, 4 Sep 2024 15:05:24 +0200 Subject: [PATCH 04/12] filter hidden directories --- .../GoogleDriveMacLocationPresetsProvider.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index ead1f86a0..509f41341 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -79,6 +79,13 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres try (var driveStream = Files.newDirectoryStream(accountPath, Files::isDirectory)) { List directories = StreamSupport.stream(driveStream.spliterator(), false).toList(); return directories.stream() + .filter(drivePath -> { + try { + return !Files.isHidden(drivePath); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) .map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath)); } catch (IOException e) { return Stream.empty(); From a03d5af14456572a17f6d94056bf285c2652c288 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Tue, 17 Sep 2024 16:49:31 +0200 Subject: [PATCH 05/12] add tilter to display only folders with write permissions --- .../locationpresets/GoogleDriveMacLocationPresetsProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index 509f41341..bf7fe3c38 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -69,6 +69,7 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres try (var dirStream = Files.list(ROOT_LOCATION)) { return dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString())) .flatMap(this::getPresetsFromAccountPath) + .filter(preset -> Files.isWritable(preset.path())) .toList().stream(); } catch (IOException | UncheckedIOException e) { return Stream.empty(); From c2c3d778d1b6b9f6f414816b924aac5fde72dbac Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Tue, 24 Sep 2024 15:29:13 +0200 Subject: [PATCH 06/12] added @CheckAvailability changed exception handling --- .../GoogleDriveMacLocationPresetsProvider.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index bf7fe3c38..ae92ed504 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -18,6 +18,7 @@ import java.util.stream.StreamSupport; import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC; @OperatingSystem(MAC) +@CheckAvailability public final class GoogleDriveMacLocationPresetsProvider implements LocationPresetsProvider { private static final Path ROOT_LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath(); private static final Predicate PATTERN = Pattern.compile("^GoogleDrive-[^/]+$").asMatchPredicate(); @@ -82,9 +83,13 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres return directories.stream() .filter(drivePath -> { try { + // Check if the directory is hidden. We want to exclude hidden directories + // from the results because they typically contain system or configuration + // files that are not relevant for the user. return !Files.isHidden(drivePath); } catch (IOException e) { - throw new RuntimeException(e); + LOG.debug("Could not determine if the path is hidden: {}", drivePath); + return false; } }) .map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath)); From fd55656261212236efa3bcd69b282cbac5bead50 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Tue, 8 Oct 2024 20:08:37 +0200 Subject: [PATCH 07/12] filtered by 'My Drive' and translations --- ...GoogleDriveMacLocationPresetsProvider.java | 93 +++++++++++++------ 1 file changed, 63 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index ae92ed504..6f4f13b4a 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -5,11 +5,12 @@ import org.cryptomator.integrations.common.OperatingSystem; import java.io.IOException; import java.io.UncheckedIOException; -import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Stream; @@ -20,6 +21,7 @@ import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC; @OperatingSystem(MAC) @CheckAvailability public final class GoogleDriveMacLocationPresetsProvider implements LocationPresetsProvider { + private static final Path ROOT_LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath(); private static final Predicate PATTERN = Pattern.compile("^GoogleDrive-[^/]+$").asMatchPredicate(); @@ -32,7 +34,7 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres @Override public Stream getLocations() { - if(isRootLocationPresent()) { + if (isRootLocationPresent()) { return getCloudStorageDirLocations(); } else { return getFallbackLocation(); @@ -44,9 +46,18 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres return isRootLocationPresent() || FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory); } + /** + * Checks if a root location directory is present that matches the specified pattern. + *

+ * This method scans the `ROOT_LOCATION` directory for subdirectories and tests each one against a pre-defined pattern. + * The method returns `true` if at least one directory is found that satisfies the pattern condition, and `false` otherwise. + * + * @return {@code true} if a matching root location is present, otherwise {@code false}. + * @throws UncheckedIOException if an I/O error occurs during directory traversal. + */ public static boolean isRootLocationPresent() { - try (DirectoryStream stream = Files.newDirectoryStream(ROOT_LOCATION, "GoogleDrive-*")) { - return StreamSupport.stream(stream.spliterator(), false).anyMatch(Files::isDirectory); + try (var dirStream = Files.list(ROOT_LOCATION)) { + return dirStream.anyMatch(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString())); } catch (IOException | UncheckedIOException e) { return false; } @@ -56,54 +67,64 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres * Returns Google Drive preset String. * * @param accountPath The path to the Google Drive account directory (e.g. {@code ~/Library/CloudStorage/GoogleDrive-username}) - * @param drivePath The path to the Google Drive file directory, within the account directory. (e.g. {@code ~/Library/CloudStorage/GoogleDrive-username/drive_name}) - * @return {@code String}. For example: "Google Drive - username - drive_name" + * @return {@code String}. For example: "Google Drive - username" */ private String getDriveLocationString(Path accountPath, Path drivePath) { String accountName = accountPath.getFileName().toString().replace("GoogleDrive-", ""); - String driveName = drivePath.getFileName().toString(); - - return STR."Google Drive - \{accountName} - \{driveName}"; + return STR."Google Drive - \{accountName}"; } + /** + * Retrieves a stream of `LocationPreset` objects from directories within the `ROOT_LOCATION` path. + *

+ * This method lists all directories in the `ROOT_LOCATION`, filters them based on whether their names match + * a predefined pattern (`PATTERN`), and then extracts presets using `getPresetsFromAccountPath(Path)`. + * The results are collected into a list and returned as a stream. + *

+ * + * @return a stream of `LocationPreset` objects representing valid cloud storage directory locations. + */ private Stream getCloudStorageDirLocations() { try (var dirStream = Files.list(ROOT_LOCATION)) { - return dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString())) - .flatMap(this::getPresetsFromAccountPath) - .filter(preset -> Files.isWritable(preset.path())) - .toList().stream(); + return dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString())).flatMap(this::getPresetsFromAccountPath).toList().stream(); } catch (IOException | UncheckedIOException e) { return Stream.empty(); } } + /** + * Retrieves a stream of `LocationPreset` objects from a given Google Drive account path. + *

+ * This method lists all directories within the provided `accountPath` and filters them + * to identify folders whose names match any of the translations defined in `MY_DRIVE_TRANSLATIONS`. + *

+ * Each matching folder is then converted into a `LocationPreset` object. + * + * @param accountPath the root path of the Google Drive account to scan. + * @return a stream of `LocationPreset` objects representing matching directories. + */ private Stream getPresetsFromAccountPath(Path accountPath) { - try (var driveStream = Files.newDirectoryStream(accountPath, Files::isDirectory)) { + try (var driveStream = Files.list(accountPath)) { List directories = StreamSupport.stream(driveStream.spliterator(), false).toList(); - return directories.stream() - .filter(drivePath -> { - try { - // Check if the directory is hidden. We want to exclude hidden directories - // from the results because they typically contain system or configuration - // files that are not relevant for the user. - return !Files.isHidden(drivePath); - } catch (IOException e) { - LOG.debug("Could not determine if the path is hidden: {}", drivePath); - return false; - } - }) - .map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath)); + return directories.stream().filter(preset -> MY_DRIVE_TRANSLATIONS.stream().anyMatch(translation -> preset.getFileName().toString().equalsIgnoreCase(translation))).map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath)); } catch (IOException e) { return Stream.empty(); } } /** - * Uses {@code FALLBACK_LOCATIONS} for directories as fallback, if {@code ~/Library/CloudStorage/} isn't present. - * Returns the corresponding presets. + * Returns a stream containing a fallback location preset for Google Drive. + *

+ * This method iterates through the predefined fallback locations, checks if any of them is a directory, + * and creates a `LocationPreset` object for the first matching directory found. The resulting stream contains + * either one preset (if a matching directory is found) or is empty. + *

+ * This method is marked as {@code @Deprecated} because it is intended for legacy support only and may be removed in future versions. * - * @return {@code Stream}. Displays as "{@code Google Drive}" + * @return a stream containing a single fallback location preset if a valid directory is found, otherwise an empty stream. + * @deprecated This method is intended for legacy support and may be removed in future releases. */ + @Deprecated private Stream getFallbackLocation() { return FALLBACK_LOCATIONS.stream() // .filter(Files::isDirectory) // @@ -111,4 +132,16 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres .findFirst() .stream(); } + + /** + * Set of translations for "My Drive" in various languages. + *

+ * This constant is used to identify different language-specific labels for "My Drive" in Google Drive. + * By using a {@link HashSet}, duplicate entries are automatically removed, ensuring a unique set of translations. + *

+ * The translations were originally extracted from the Chromium project’s Chrome OS translation files. + *

+ * Source: `ui/chromeos/translations` directory in the Chromium repository. + */ + private static final Set MY_DRIVE_TRANSLATIONS = new HashSet<>(List.of("My Drive", "የእኔ Drive", "ملفاتي", "মোৰ ড্ৰাইভ", "Diskim", "Мой Дыск", "Моят диск", "আমার ড্রাইভ", "Moj disk", "La meva unitat", "Můj disk", "My Drive", "Mit drev", "Meine Ablage", "Το Drive μου", "My Drive", "Mi unidad", "Mi unidad", "Minu ketas", "Nire unitatea", "My Drive", "Aking Drive", "Oma Drive", "Mon disque", "Mon Drive", "A miña unidade", "મારી ડ્રાઇવ", "मेरी ड्राइव", "Moj disk", "Saját meghajtó", "Իմ դրայվը", "Drive Saya", "Drifið mitt", "I miei file", "האחסון שלי", "マイドライブ", "ჩემი Drive", "Менің Drive дискім", "ដ្រាយរបស់ខ្ញុំ", "ನನ್ನ ಡ್ರೈವ್", "내 드라이브", "Менин Drive'ым", "My Drive", "Mano Diskas", "Mans disks", "Мојот Drive", "എന്റെ ഡ്രൈവ്", "Миний Драйв", "माझा ड्राइव्ह", "Drive Saya", "My Drive", "मेरो ड्राइभ", "Mijn Drive", "Min disk", "ମୋ ଡ୍ରାଇଭ୍", "My Drive", "Mój dysk", "Meu Drive", "O meu disco", "Contul meu Drive", "Мой диск", "මගේ Drive", "Môj disk", "Moj disk", "Disku im", "Moj disk", "Мој диск", "Min enhet", "Hifadhi Yangu", "எனது இயக்ககம்", "నా డ్రైవ్‌", "ไดรฟ์ของฉัน", "Drive'ım", "Мій диск", "میری ڈرائیو", "My Drive", "Drive của tôi", "我的云端硬盘", "我的雲端硬碟", "我的雲端硬碟", "IDrayivu yami")); } From 98db82d13738e1f9bc510e9acf4af6ed1b004e38 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Wed, 9 Oct 2024 14:48:40 +0200 Subject: [PATCH 08/12] contains instead of stream --- .../GoogleDriveMacLocationPresetsProvider.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index 6f4f13b4a..2bf952e82 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -106,7 +106,13 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres private Stream getPresetsFromAccountPath(Path accountPath) { try (var driveStream = Files.list(accountPath)) { List directories = StreamSupport.stream(driveStream.spliterator(), false).toList(); - return directories.stream().filter(preset -> MY_DRIVE_TRANSLATIONS.stream().anyMatch(translation -> preset.getFileName().toString().equalsIgnoreCase(translation))).map(drivePath -> new LocationPreset(getDriveLocationString(accountPath, drivePath), drivePath)); + return directories.stream() + .filter(preset -> MY_DRIVE_TRANSLATIONS + .contains(preset.getFileName().toString())) + .map(drivePath -> new LocationPreset( + getDriveLocationString(accountPath, drivePath), + drivePath + )); } catch (IOException e) { return Stream.empty(); } From 2dce7b6f711ae98f0002d0219c3bb97ef90af746 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Wed, 9 Oct 2024 14:50:05 +0200 Subject: [PATCH 09/12] removed drivePath param --- .../GoogleDriveMacLocationPresetsProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index 2bf952e82..65c913dee 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -69,7 +69,7 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres * @param accountPath The path to the Google Drive account directory (e.g. {@code ~/Library/CloudStorage/GoogleDrive-username}) * @return {@code String}. For example: "Google Drive - username" */ - private String getDriveLocationString(Path accountPath, Path drivePath) { + private String getDriveLocationString(Path accountPath) { String accountName = accountPath.getFileName().toString().replace("GoogleDrive-", ""); return STR."Google Drive - \{accountName}"; } @@ -110,7 +110,7 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres .filter(preset -> MY_DRIVE_TRANSLATIONS .contains(preset.getFileName().toString())) .map(drivePath -> new LocationPreset( - getDriveLocationString(accountPath, drivePath), + getDriveLocationString(accountPath), drivePath )); } catch (IOException e) { From 764fccf0b546f05bd46ca42d04e5aaed1af5e9f5 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Thu, 10 Oct 2024 17:34:23 +0200 Subject: [PATCH 10/12] pr mentioned changes --- ...GoogleDriveMacLocationPresetsProvider.java | 60 +++++++++---------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index 65c913dee..88ac67707 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -34,11 +34,9 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres @Override public Stream getLocations() { - if (isRootLocationPresent()) { - return getCloudStorageDirLocations(); - } else { - return getFallbackLocation(); - } + List cloudStorageDirLocations = getCloudStorageDirLocations(); + return cloudStorageDirLocations.isEmpty() ? getFallbackLocation().stream() : cloudStorageDirLocations.stream(); + } @CheckAvailability @@ -49,11 +47,9 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres /** * Checks if a root location directory is present that matches the specified pattern. *

- * This method scans the `ROOT_LOCATION` directory for subdirectories and tests each one against a pre-defined pattern. - * The method returns `true` if at least one directory is found that satisfies the pattern condition, and `false` otherwise. + * This method scans the {@code ROOT_LOCATION} directory for subdirectories and tests each one against a pre-defined pattern ({@code PATTERN}). * * @return {@code true} if a matching root location is present, otherwise {@code false}. - * @throws UncheckedIOException if an I/O error occurs during directory traversal. */ public static boolean isRootLocationPresent() { try (var dirStream = Files.list(ROOT_LOCATION)) { @@ -75,33 +71,34 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres } /** - * Retrieves a stream of `LocationPreset` objects from directories within the `ROOT_LOCATION` path. + * Retrieves a list of cloud storage directory locations based on the {@code ROOT_LOCATION}. *

- * This method lists all directories in the `ROOT_LOCATION`, filters them based on whether their names match - * a predefined pattern (`PATTERN`), and then extracts presets using `getPresetsFromAccountPath(Path)`. - * The results are collected into a list and returned as a stream. + * This method lists all directories in the {@code ROOT_LOCATION}, filters them based on whether their names match + * a predefined pattern ({@code PATTERN}), and then extracts presets using {@code getPresetsFromAccountPath(Path)}. *

* - * @return a stream of `LocationPreset` objects representing valid cloud storage directory locations. + * @return a list of {@code LocationPreset} objects representing valid cloud storage directory locations. */ - private Stream getCloudStorageDirLocations() { + private List getCloudStorageDirLocations() { try (var dirStream = Files.list(ROOT_LOCATION)) { - return dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString())).flatMap(this::getPresetsFromAccountPath).toList().stream(); + return dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString())) + .flatMap(this::getPresetsFromAccountPath) + .toList(); } catch (IOException | UncheckedIOException e) { - return Stream.empty(); + return List.of(); } } /** - * Retrieves a stream of `LocationPreset` objects from a given Google Drive account path. + * Retrieves a stream of {@code LocationPreset} objects from a given Google Drive account path. *

- * This method lists all directories within the provided `accountPath` and filters them - * to identify folders whose names match any of the translations defined in `MY_DRIVE_TRANSLATIONS`. + * This method lists all directories within the provided {@code accountPath} and filters them + * to identify folders whose names match any of the translations defined in {@code MY_DRIVE_TRANSLATIONS}. *

- * Each matching folder is then converted into a `LocationPreset` object. + * Each matching folder is then converted into a {@code LocationPreset} object. * * @param accountPath the root path of the Google Drive account to scan. - * @return a stream of `LocationPreset` objects representing matching directories. + * @return a stream of {@code LocationPreset} objects representing matching directories. */ private Stream getPresetsFromAccountPath(Path accountPath) { try (var driveStream = Files.list(accountPath)) { @@ -119,35 +116,32 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres } /** - * Returns a stream containing a fallback location preset for Google Drive. + * Returns a list containing a fallback location preset for Google Drive. *

* This method iterates through the predefined fallback locations, checks if any of them is a directory, - * and creates a `LocationPreset` object for the first matching directory found. The resulting stream contains - * either one preset (if a matching directory is found) or is empty. - *

- * This method is marked as {@code @Deprecated} because it is intended for legacy support only and may be removed in future versions. + * and creates a {@code LocationPreset} object for the first matching directory found. * - * @return a stream containing a single fallback location preset if a valid directory is found, otherwise an empty stream. + * @return a list containing a single fallback location preset if a valid directory is found, otherwise an empty list. * @deprecated This method is intended for legacy support and may be removed in future releases. */ @Deprecated - private Stream getFallbackLocation() { - return FALLBACK_LOCATIONS.stream() // - .filter(Files::isDirectory) // + private List getFallbackLocation() { + return FALLBACK_LOCATIONS.stream() + .filter(Files::isDirectory) .map(location -> new LocationPreset("Google Drive", location)) .findFirst() - .stream(); + .stream() + .toList(); } /** * Set of translations for "My Drive" in various languages. *

* This constant is used to identify different language-specific labels for "My Drive" in Google Drive. - * By using a {@link HashSet}, duplicate entries are automatically removed, ensuring a unique set of translations. *

* The translations were originally extracted from the Chromium project’s Chrome OS translation files. *

* Source: `ui/chromeos/translations` directory in the Chromium repository. */ - private static final Set MY_DRIVE_TRANSLATIONS = new HashSet<>(List.of("My Drive", "የእኔ Drive", "ملفاتي", "মোৰ ড্ৰাইভ", "Diskim", "Мой Дыск", "Моят диск", "আমার ড্রাইভ", "Moj disk", "La meva unitat", "Můj disk", "My Drive", "Mit drev", "Meine Ablage", "Το Drive μου", "My Drive", "Mi unidad", "Mi unidad", "Minu ketas", "Nire unitatea", "My Drive", "Aking Drive", "Oma Drive", "Mon disque", "Mon Drive", "A miña unidade", "મારી ડ્રાઇવ", "मेरी ड्राइव", "Moj disk", "Saját meghajtó", "Իմ դրայվը", "Drive Saya", "Drifið mitt", "I miei file", "האחסון שלי", "マイドライブ", "ჩემი Drive", "Менің Drive дискім", "ដ្រាយរបស់ខ្ញុំ", "ನನ್ನ ಡ್ರೈವ್", "내 드라이브", "Менин Drive'ым", "My Drive", "Mano Diskas", "Mans disks", "Мојот Drive", "എന്റെ ഡ്രൈവ്", "Миний Драйв", "माझा ड्राइव्ह", "Drive Saya", "My Drive", "मेरो ड्राइभ", "Mijn Drive", "Min disk", "ମୋ ଡ୍ରାଇଭ୍", "My Drive", "Mój dysk", "Meu Drive", "O meu disco", "Contul meu Drive", "Мой диск", "මගේ Drive", "Môj disk", "Moj disk", "Disku im", "Moj disk", "Мој диск", "Min enhet", "Hifadhi Yangu", "எனது இயக்ககம்", "నా డ్రైవ్‌", "ไดรฟ์ของฉัน", "Drive'ım", "Мій диск", "میری ڈرائیو", "My Drive", "Drive của tôi", "我的云端硬盘", "我的雲端硬碟", "我的雲端硬碟", "IDrayivu yami")); + private static final Set MY_DRIVE_TRANSLATIONS = Set.of("My Drive", "የእኔ Drive", "ملفاتي", "মোৰ ড্ৰাইভ", "Diskim", "Мой Дыск", "Моят диск", "আমার ড্রাইভ", "Moj disk", "La meva unitat", "Můj disk", "Mit drev", "Meine Ablage", "Το Drive μου", "Mi unidad", "Minu ketas", "Nire unitatea", "Aking Drive", "Oma Drive", "Mon disque", "Mon Drive", "A miña unidade", "મારી ડ્રાઇવ", "मेरी ड्राइव", "Saját meghajtó", "Իմ դրայվը", "Drive Saya", "Drifið mitt", "I miei file", "האחסון שלי", "マイドライブ", "ჩემი Drive", "Менің Drive дискім", "ដ្រាយរបស់ខ្ញុំ", "ನನ್ನ ಡ್ರೈವ್", "내 드라이브", "Менин Drive'ым", "Mano Diskas", "Mans disks", "Мојот Drive", "എന്റെ ഡ്രൈവ്", "Миний Драйв", "माझा ड्राइव्ह", "मेरो ड्राइभ", "Mijn Drive", "Min disk", "ମୋ ଡ୍ରାଇଭ୍", "Mój dysk", "Meu Drive", "O meu disco", "Contul meu Drive", "Мой диск", "මගේ Drive", "Môj disk", "Disku im", "Мој диск", "Min enhet", "Hifadhi Yangu", "எனது இயக்ககம்", "నా డ్రైవ్‌", "ไดรฟ์ของฉัน", "Drive'ım", "Мій диск", "میری ڈرائیو", "Drive của tôi", "我的云端硬盘", "我的雲端硬碟", "IDrayivu yami"); } From 4b359d98cbba858262fc33473d0cc1535edc9217 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Thu, 10 Oct 2024 17:39:53 +0200 Subject: [PATCH 11/12] removed unnecessary stream support --- .../GoogleDriveMacLocationPresetsProvider.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index 88ac67707..7dd92279f 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -94,22 +94,19 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres *

* This method lists all directories within the provided {@code accountPath} and filters them * to identify folders whose names match any of the translations defined in {@code MY_DRIVE_TRANSLATIONS}. - *

- * Each matching folder is then converted into a {@code LocationPreset} object. * * @param accountPath the root path of the Google Drive account to scan. * @return a stream of {@code LocationPreset} objects representing matching directories. */ private Stream getPresetsFromAccountPath(Path accountPath) { try (var driveStream = Files.list(accountPath)) { - List directories = StreamSupport.stream(driveStream.spliterator(), false).toList(); - return directories.stream() + return driveStream .filter(preset -> MY_DRIVE_TRANSLATIONS .contains(preset.getFileName().toString())) .map(drivePath -> new LocationPreset( getDriveLocationString(accountPath), drivePath - )); + )).toList().stream(); } catch (IOException e) { return Stream.empty(); } From f6421497236d0ba8f6992e3732d84be8e5ad7bd6 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Wed, 16 Oct 2024 18:00:47 +0200 Subject: [PATCH 12/12] used List.of() for FALLBACK_LOCATIONS --- .../locationpresets/GoogleDriveMacLocationPresetsProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java index 7dd92279f..9cb428d1b 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/GoogleDriveMacLocationPresetsProvider.java @@ -25,7 +25,7 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres private static final Path ROOT_LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath(); private static final Predicate PATTERN = Pattern.compile("^GoogleDrive-[^/]+$").asMatchPredicate(); - private static final List FALLBACK_LOCATIONS = Arrays.asList( // + private static final List FALLBACK_LOCATIONS = List.of( // LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive"), // LocationPresetsProvider.resolveLocation("~/Google Drive/My Drive"), // LocationPresetsProvider.resolveLocation("~/GoogleDrive"), //