From fd0b30d22a89f1661aa8ae9dd31af6724fe8a87f Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 13 Oct 2022 16:37:53 +0200 Subject: [PATCH 01/46] bump versions of used gh actions --- .github/workflows/build.yml | 8 ++++---- .github/workflows/codeql-analysis.yml | 8 ++++---- .github/workflows/publish-central.yml | 4 ++-- .github/workflows/publish-github.yml | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 36cb45e..a7a9b82 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,8 +7,8 @@ jobs: runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: 17 @@ -19,12 +19,12 @@ jobs: - name: Build and Test id: buildAndTest run: mvn -B clean install - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: artifacts path: target/*.jar - name: Create Release - uses: actions/create-release@v1 + uses: actions/create-release@v1 # NOTE: action is unmaintained and repo archived if: startsWith(github.ref, 'refs/tags/') env: GITHUB_TOKEN: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} # release as "cryptobot" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c95b54d..7eedd35 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -15,19 +15,19 @@ jobs: runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 2 - - uses: actions/setup-java@v2 + - uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: 17 cache: 'maven' - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: java - name: Build run: mvn -B compile - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 \ No newline at end of file + uses: github/codeql-action/analyze@v2 \ No newline at end of file diff --git a/.github/workflows/publish-central.yml b/.github/workflows/publish-central.yml index f3897af..6cecb12 100644 --- a/.github/workflows/publish-central.yml +++ b/.github/workflows/publish-central.yml @@ -10,10 +10,10 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: "refs/tags/${{ github.event.inputs.tag }}" - - uses: actions/setup-java@v2 + - uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: 17 diff --git a/.github/workflows/publish-github.yml b/.github/workflows/publish-github.yml index 885c659..309a8ac 100644 --- a/.github/workflows/publish-github.yml +++ b/.github/workflows/publish-github.yml @@ -7,8 +7,8 @@ jobs: runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/') # only allow publishing tagged versions steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: 17 From 090f2d94223ff60ab58e5d63e270ce9bd2471aee Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 25 Oct 2022 12:51:55 +0200 Subject: [PATCH 02/46] first draft for vfs/mount provider api --- .../mount/MountFailedException.java | 8 ++ .../integrations/mount/MountProvider.java | 74 +++++++++++++++++++ .../mount/UnmountFailedException.java | 12 +++ 3 files changed, 94 insertions(+) create mode 100644 src/main/java/org/cryptomator/integrations/mount/MountFailedException.java create mode 100644 src/main/java/org/cryptomator/integrations/mount/MountProvider.java create mode 100644 src/main/java/org/cryptomator/integrations/mount/UnmountFailedException.java diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFailedException.java b/src/main/java/org/cryptomator/integrations/mount/MountFailedException.java new file mode 100644 index 0000000..ef7f04b --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/MountFailedException.java @@ -0,0 +1,8 @@ +package org.cryptomator.integrations.mount; + +public class MountFailedException extends Exception { + + public MountFailedException(Exception e) { + super(e); + } +} diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java new file mode 100644 index 0000000..1fa3212 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java @@ -0,0 +1,74 @@ +package org.cryptomator.integrations.mount; + +import org.cryptomator.integrations.common.IntegrationsLoader; + +import java.nio.file.Path; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Stream; + +public interface MountProvider { + + /** + * Loads the best-suited AutoStartProvider. + * + * @return preferred AutoStartProvider (if any) + * @since 1.1.0 + */ + static Stream get() { + return IntegrationsLoader.loadAll(MountProvider.class).filter(MountProvider::isSupported); + } + + String displayName(); + + boolean isSupported(); + + MountBuilder forPath(Path vfsRoot); + + interface MountedVolume extends AutoCloseable { + + //TODO: either this or reveal method, not both + Path getAccessPoint(); + + //TODO: is this needed? why not just let the consumer reveal? + void reveal(Consumer cmd); + + void unmout() throws UnmountFailedException; + + default void close() throws UnmountFailedException { + unmout(); + } + } + + //ALL FEATURES + enum Features { + CUSTOM_FLAGS, + MOUNT_POINT_EMPTY_DIR, + MOUNT_POINT_DRIVE_LETTER, + READ_ONLY, + FORCED_UNMOUNT, + ON_EXIT_ACTION, + PORT + } + + Set supportedFeatures(); + + //TODO: if not supported No-op or throw? + // no-op better for unified code (just load off all shiat into the builder and see what the result is) + // does not hold for invalid input + interface MountBuilder { + + MountBuilder setMountpoint(Path p); //TODO: Idea: every setter verifies the set and can throw an IllegalArgumentException + + MountBuilder setOnExitAction(Consumer onExitAction); + + MountBuilder setCustomFlags(String customFlags); + + MountBuilder setReadOnly(boolean mountReadOnly); + + MountedVolume mount() throws MountFailedException; + + } + + +} diff --git a/src/main/java/org/cryptomator/integrations/mount/UnmountFailedException.java b/src/main/java/org/cryptomator/integrations/mount/UnmountFailedException.java new file mode 100644 index 0000000..3ed1c1f --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/UnmountFailedException.java @@ -0,0 +1,12 @@ +package org.cryptomator.integrations.mount; + +public class UnmountFailedException extends Exception { + + public UnmountFailedException() { + super(); + } + + public UnmountFailedException(Exception e) { + super(e); + } +} From 5ca03c3bcf5d1b820549bb97bcb489407fc38fcd Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 26 Oct 2022 12:02:22 +0200 Subject: [PATCH 03/46] declare mount service in module-info --- src/main/java/module-info.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 12d8bd4..cddd5d0 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,3 +1,4 @@ +import org.cryptomator.integrations.mount.MountProvider; import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.keychain.KeychainAccessProvider; @@ -12,11 +13,13 @@ exports org.cryptomator.integrations.autostart; exports org.cryptomator.integrations.common; exports org.cryptomator.integrations.keychain; + exports org.cryptomator.integrations.mount; exports org.cryptomator.integrations.tray; exports org.cryptomator.integrations.uiappearance; uses AutoStartProvider; uses KeychainAccessProvider; + uses MountProvider; uses TrayIntegrationProvider; uses TrayMenuController; uses UiAppearanceProvider; From fadf3057208b999ab2aa677d4a099d4316feb594 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 26 Oct 2022 16:22:56 +0200 Subject: [PATCH 04/46] add more constructors to (un)mount exceptions --- .../integrations/mount/MountFailedException.java | 12 ++++++++++-- .../integrations/mount/UnmountFailedException.java | 12 ++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFailedException.java b/src/main/java/org/cryptomator/integrations/mount/MountFailedException.java index ef7f04b..c22556f 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountFailedException.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountFailedException.java @@ -2,7 +2,15 @@ public class MountFailedException extends Exception { - public MountFailedException(Exception e) { - super(e); + public MountFailedException(String msg) { + super(msg); + } + + public MountFailedException(Exception cause) { + super(cause); + } + + public MountFailedException(String msg, Exception cause) { + super(msg, cause); } } diff --git a/src/main/java/org/cryptomator/integrations/mount/UnmountFailedException.java b/src/main/java/org/cryptomator/integrations/mount/UnmountFailedException.java index 3ed1c1f..2babcc4 100644 --- a/src/main/java/org/cryptomator/integrations/mount/UnmountFailedException.java +++ b/src/main/java/org/cryptomator/integrations/mount/UnmountFailedException.java @@ -2,11 +2,15 @@ public class UnmountFailedException extends Exception { - public UnmountFailedException() { - super(); + public UnmountFailedException(String msg) { + super(msg); } - public UnmountFailedException(Exception e) { - super(e); + public UnmountFailedException(Exception cause) { + super(cause); + } + + public UnmountFailedException(String msg, Exception cause) { + super(msg, cause); } } From 2e96808a8917b239df06fdb8f792c1039e54b4ed Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 26 Oct 2022 16:32:06 +0200 Subject: [PATCH 05/46] extend mout api --- .../integrations/mount/MountProvider.java | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java index 1fa3212..4a43594 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java @@ -25,6 +25,16 @@ static Stream get() { MountBuilder forPath(Path vfsRoot); + default String getDefaultMountPoint() { + throw new UnsupportedOperationException(); + } + + default String getDefaultMountFlags() { + throw new UnsupportedOperationException(); + } + + ; + interface MountedVolume extends AutoCloseable { //TODO: either this or reveal method, not both @@ -35,6 +45,10 @@ interface MountedVolume extends AutoCloseable { void unmout() throws UnmountFailedException; + default void unmountForced() throws UnmountFailedException { + throw new UnsupportedOperationException(); + } + default void close() throws UnmountFailedException { unmout(); } @@ -45,26 +59,41 @@ enum Features { CUSTOM_FLAGS, MOUNT_POINT_EMPTY_DIR, MOUNT_POINT_DRIVE_LETTER, + MOUNT_POINT_PATH_PREFIX, READ_ONLY, - FORCED_UNMOUNT, + UNMOUNT_FORCED, ON_EXIT_ACTION, - PORT + PORT, + DEFAULT_MOUNT_POINT, + DEFAULT_MOUNT_FLAGS } Set supportedFeatures(); - //TODO: if not supported No-op or throw? - // no-op better for unified code (just load off all shiat into the builder and see what the result is) - // does not hold for invalid input + /** + * Builder to mount a virtual filesystem. + *

+ * The setter may validate the input, but no guarantee is given that the final mount option does not fail due to invalid input. + * This holds especially for {@link this#setMountFlags(String)}; + */ interface MountBuilder { - MountBuilder setMountpoint(Path p); //TODO: Idea: every setter verifies the set and can throw an IllegalArgumentException + //TODO: Idea: every setter verifies the set and can throw an IllegalArgumentException + default MountBuilder setMountpoint(Path p) { + throw new UnsupportedOperationException(); + } - MountBuilder setOnExitAction(Consumer onExitAction); + default MountBuilder setOnExitAction(Consumer onExitAction) { + throw new UnsupportedOperationException(); + } - MountBuilder setCustomFlags(String customFlags); + default MountBuilder setMountFlags(String mountFlags) { + throw new UnsupportedOperationException(); + } - MountBuilder setReadOnly(boolean mountReadOnly); + default MountBuilder setReadOnly(boolean mountReadOnly) { + throw new UnsupportedOperationException(); + } MountedVolume mount() throws MountFailedException; From 03a85cbcf7316cc6a7f11937b092840785930cc6 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 26 Oct 2022 16:43:16 +0200 Subject: [PATCH 06/46] improve javadoc --- .../cryptomator/integrations/mount/MountProvider.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java index 4a43594..dbd1b70 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java @@ -43,6 +43,15 @@ interface MountedVolume extends AutoCloseable { //TODO: is this needed? why not just let the consumer reveal? void reveal(Consumer cmd); + /** + * Unmounts the mounted Volume. + *

+ * The unmount procedure should be as gracefule as possible. + * If the volume supports a forceful unmount, see {@link MountedVolume#unmountForced()} can be used. + * The most harsh unmount happens by using {@link MountedVolume#close()}. + * + * @throws UnmountFailedException If the unmount was not successful. + */ void unmout() throws UnmountFailedException; default void unmountForced() throws UnmountFailedException { @@ -74,7 +83,7 @@ enum Features { * Builder to mount a virtual filesystem. *

* The setter may validate the input, but no guarantee is given that the final mount option does not fail due to invalid input. - * This holds especially for {@link this#setMountFlags(String)}; + * This holds especially for {@link MountBuilder#setMountFlags(String)}; */ interface MountBuilder { From 3c0bc6ed06ec11e6fd5918ee5b0c7ca6581bd7e1 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 26 Oct 2022 19:55:46 +0200 Subject: [PATCH 07/46] Refactor of mount API (mostly renaming and moving classes) --- src/main/java/module-info.java | 4 +- .../integrations/mount/FileSystemMount.java | 68 +++++++++++ .../mount/FilesystemMountProvider.java | 91 ++++++++++++++ .../integrations/mount/MountFeature.java | 13 ++ .../integrations/mount/MountProvider.java | 112 ------------------ 5 files changed, 174 insertions(+), 114 deletions(-) create mode 100644 src/main/java/org/cryptomator/integrations/mount/FileSystemMount.java create mode 100644 src/main/java/org/cryptomator/integrations/mount/FilesystemMountProvider.java create mode 100644 src/main/java/org/cryptomator/integrations/mount/MountFeature.java delete mode 100644 src/main/java/org/cryptomator/integrations/mount/MountProvider.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index cddd5d0..21398d4 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,4 +1,4 @@ -import org.cryptomator.integrations.mount.MountProvider; +import org.cryptomator.integrations.mount.FilesystemMountProvider; import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.keychain.KeychainAccessProvider; @@ -19,7 +19,7 @@ uses AutoStartProvider; uses KeychainAccessProvider; - uses MountProvider; + uses FilesystemMountProvider; uses TrayIntegrationProvider; uses TrayMenuController; uses UiAppearanceProvider; diff --git a/src/main/java/org/cryptomator/integrations/mount/FileSystemMount.java b/src/main/java/org/cryptomator/integrations/mount/FileSystemMount.java new file mode 100644 index 0000000..625f59f --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/FileSystemMount.java @@ -0,0 +1,68 @@ +package org.cryptomator.integrations.mount; + +import java.nio.file.Path; +import java.util.function.Consumer; + +/** + * A filesystem mounted into the OS. + * + * Created by {@link FileSystemMount.Builder} + */ +public interface FileSystemMount extends AutoCloseable { + + //TODO: either this or reveal method, not both + Path getAccessPoint(); + + //TODO: is this needed? why not just let the consumer reveal? + void reveal(Consumer cmd); + + /** + * Unmounts the mounted Volume. + *

+ * The unmount procedure should be as gracefule as possible. + * If the volume supports a forceful unmount, see {@link FileSystemMount#unmountForced()} can be used. + * The most harsh unmount happens by using {@link FileSystemMount#close()}. + * + * @throws UnmountFailedException If the unmount was not successful. + */ + void unmout() throws UnmountFailedException; + + default void unmountForced() throws UnmountFailedException { + throw new UnsupportedOperationException(); + } + + default void close() throws UnmountFailedException { + unmout(); + } + + + + /** + * Builder to mount a filesystem. + *

+ * The setter may validate the input, but no guarantee is given that the final mount option does not fail due to invalid input. + * This holds especially for {@link Builder#setMountFlags(String)}; + */ + interface Builder { + + //TODO: Idea: every setter verifies the set and can throw an IllegalArgumentException + default Builder setMountpoint(Path p) { + throw new UnsupportedOperationException(); + } + + default Builder setOnExitAction(Consumer onExitAction) { + throw new UnsupportedOperationException(); + } + + default Builder setMountFlags(String mountFlags) { + throw new UnsupportedOperationException(); + } + + default Builder setReadOnly(boolean mountReadOnly) { + throw new UnsupportedOperationException(); + } + + FileSystemMount mount() throws MountFailedException; + + } +} diff --git a/src/main/java/org/cryptomator/integrations/mount/FilesystemMountProvider.java b/src/main/java/org/cryptomator/integrations/mount/FilesystemMountProvider.java new file mode 100644 index 0000000..7e9165f --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/FilesystemMountProvider.java @@ -0,0 +1,91 @@ +package org.cryptomator.integrations.mount; + +import org.cryptomator.integrations.common.IntegrationsLoader; + +import java.nio.file.Path; +import java.util.Set; +import java.util.stream.Stream; + +/** + * Vorteile: + * * IoC: Ein Provider weiß was er kann und was nicht! + * * Wegfall der komplizierten Mountpoint Logik + * * App beschränkt sich mehr auf GUI und Logik darum + * * Einfaches ändern/entfernen eines Providers + * * Mounten ist eine Systemintegration! + * * Tests!? + * * Illegal Mount Options Check? + * * In der GUI sieht der Nutzer sofort, was sich ändert. + *

+ * Nachteile: + * * Code-Duplikation + * * WebDAV-ServerPort? (-> Legacy Option in Preferences?) + *

+ * Ungeklärt: + * * Anzeigen von Fehler dem User (-> Translations nutzbar?) + * * Langfristiger Wechsel zu eigenständigen Prozessen? + */ +public interface FilesystemMountProvider { + + /** + * Loads all supported MountProvider. + * + * @return Stream of supported MountProviders + * @since 1.1.0 + */ + static Stream get() { + return IntegrationsLoader.loadAll(FilesystemMountProvider.class).filter(FilesystemMountProvider::isSupported); + } + + /** + * Name of this provider + * + * @return A human readable name of this provider + */ + String displayName(); + + /** + * Indicates, if this provider can be used. + * + * @return true, if this provider is supported in the current OS environment + */ + boolean isSupported(); + + + /** + * A default mountpoint any filesystem can be mounted to. + * Note, that this method: + *

    + *
  1. method is optional. If not implemented, throws an {@link UnsupportedOperationException}
  2. + *
  3. is not required to serve static content. It should be considerer as a "mount point maker" with the implemetnation as the template engine
  4. + *
+ * + * @param mountPointSuffix String used in the generation of a mount point. + * @return A path to a possible mount point. + */ + default Path getDefaultMountPoint(String mountPointSuffix) { + throw new UnsupportedOperationException(); + } + + /** + * Default mount flags. + * Implementation required if feature {@link MountFeature#MOUNT_FLAGS} is supported. + * + * @param mountName Name of the mount in the OS + * @return Concatenated String of valid mount flags + */ + default String getDefaultMountFlags(String mountName) { + throw new UnsupportedOperationException(); + } + + /** + * Mount features supported by this provider. + * + * @return Set of supported {@link MountFeature}s + */ + Set supportedFeatures(); + + + FileSystemMount.Builder forFileSystem(Path fileSystemRoot); + +} diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java new file mode 100644 index 0000000..e3d78e2 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java @@ -0,0 +1,13 @@ +package org.cryptomator.integrations.mount; + +public enum MountFeature { + MOUNT_FLAGS, + MOUNT_POINT_EMPTY_DIR, + MOUNT_POINT_DRIVE_LETTER, + MOUNT_POINT_PATH_PREFIX, + READ_ONLY, + UNMOUNT_FORCED, + ON_EXIT_ACTION, + PORT, + DEFAULT_MOUNT_POINT +} diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java deleted file mode 100644 index dbd1b70..0000000 --- a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.cryptomator.integrations.mount; - -import org.cryptomator.integrations.common.IntegrationsLoader; - -import java.nio.file.Path; -import java.util.Set; -import java.util.function.Consumer; -import java.util.stream.Stream; - -public interface MountProvider { - - /** - * Loads the best-suited AutoStartProvider. - * - * @return preferred AutoStartProvider (if any) - * @since 1.1.0 - */ - static Stream get() { - return IntegrationsLoader.loadAll(MountProvider.class).filter(MountProvider::isSupported); - } - - String displayName(); - - boolean isSupported(); - - MountBuilder forPath(Path vfsRoot); - - default String getDefaultMountPoint() { - throw new UnsupportedOperationException(); - } - - default String getDefaultMountFlags() { - throw new UnsupportedOperationException(); - } - - ; - - interface MountedVolume extends AutoCloseable { - - //TODO: either this or reveal method, not both - Path getAccessPoint(); - - //TODO: is this needed? why not just let the consumer reveal? - void reveal(Consumer cmd); - - /** - * Unmounts the mounted Volume. - *

- * The unmount procedure should be as gracefule as possible. - * If the volume supports a forceful unmount, see {@link MountedVolume#unmountForced()} can be used. - * The most harsh unmount happens by using {@link MountedVolume#close()}. - * - * @throws UnmountFailedException If the unmount was not successful. - */ - void unmout() throws UnmountFailedException; - - default void unmountForced() throws UnmountFailedException { - throw new UnsupportedOperationException(); - } - - default void close() throws UnmountFailedException { - unmout(); - } - } - - //ALL FEATURES - enum Features { - CUSTOM_FLAGS, - MOUNT_POINT_EMPTY_DIR, - MOUNT_POINT_DRIVE_LETTER, - MOUNT_POINT_PATH_PREFIX, - READ_ONLY, - UNMOUNT_FORCED, - ON_EXIT_ACTION, - PORT, - DEFAULT_MOUNT_POINT, - DEFAULT_MOUNT_FLAGS - } - - Set supportedFeatures(); - - /** - * Builder to mount a virtual filesystem. - *

- * The setter may validate the input, but no guarantee is given that the final mount option does not fail due to invalid input. - * This holds especially for {@link MountBuilder#setMountFlags(String)}; - */ - interface MountBuilder { - - //TODO: Idea: every setter verifies the set and can throw an IllegalArgumentException - default MountBuilder setMountpoint(Path p) { - throw new UnsupportedOperationException(); - } - - default MountBuilder setOnExitAction(Consumer onExitAction) { - throw new UnsupportedOperationException(); - } - - default MountBuilder setMountFlags(String mountFlags) { - throw new UnsupportedOperationException(); - } - - default MountBuilder setReadOnly(boolean mountReadOnly) { - throw new UnsupportedOperationException(); - } - - MountedVolume mount() throws MountFailedException; - - } - - -} From 3365a7aff86744e89e38b20a1211c5e66cb7e00c Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 26 Oct 2022 21:30:47 +0200 Subject: [PATCH 08/46] refined API --- src/main/java/module-info.java | 4 +- .../integrations/mount/FileSystemMount.java | 68 ----------- .../mount/FilesystemMountProvider.java | 91 -------------- .../cryptomator/integrations/mount/Mount.java | 45 +++++++ .../integrations/mount/MountBuilder.java | 85 +++++++++++++ .../integrations/mount/MountFeature.java | 26 ++++ .../integrations/mount/MountProvider.java | 112 ++++++++++++++++++ 7 files changed, 270 insertions(+), 161 deletions(-) delete mode 100644 src/main/java/org/cryptomator/integrations/mount/FileSystemMount.java delete mode 100644 src/main/java/org/cryptomator/integrations/mount/FilesystemMountProvider.java create mode 100644 src/main/java/org/cryptomator/integrations/mount/Mount.java create mode 100644 src/main/java/org/cryptomator/integrations/mount/MountBuilder.java create mode 100644 src/main/java/org/cryptomator/integrations/mount/MountProvider.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 21398d4..cddd5d0 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,4 +1,4 @@ -import org.cryptomator.integrations.mount.FilesystemMountProvider; +import org.cryptomator.integrations.mount.MountProvider; import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.keychain.KeychainAccessProvider; @@ -19,7 +19,7 @@ uses AutoStartProvider; uses KeychainAccessProvider; - uses FilesystemMountProvider; + uses MountProvider; uses TrayIntegrationProvider; uses TrayMenuController; uses UiAppearanceProvider; diff --git a/src/main/java/org/cryptomator/integrations/mount/FileSystemMount.java b/src/main/java/org/cryptomator/integrations/mount/FileSystemMount.java deleted file mode 100644 index 625f59f..0000000 --- a/src/main/java/org/cryptomator/integrations/mount/FileSystemMount.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.cryptomator.integrations.mount; - -import java.nio.file.Path; -import java.util.function.Consumer; - -/** - * A filesystem mounted into the OS. - * - * Created by {@link FileSystemMount.Builder} - */ -public interface FileSystemMount extends AutoCloseable { - - //TODO: either this or reveal method, not both - Path getAccessPoint(); - - //TODO: is this needed? why not just let the consumer reveal? - void reveal(Consumer cmd); - - /** - * Unmounts the mounted Volume. - *

- * The unmount procedure should be as gracefule as possible. - * If the volume supports a forceful unmount, see {@link FileSystemMount#unmountForced()} can be used. - * The most harsh unmount happens by using {@link FileSystemMount#close()}. - * - * @throws UnmountFailedException If the unmount was not successful. - */ - void unmout() throws UnmountFailedException; - - default void unmountForced() throws UnmountFailedException { - throw new UnsupportedOperationException(); - } - - default void close() throws UnmountFailedException { - unmout(); - } - - - - /** - * Builder to mount a filesystem. - *

- * The setter may validate the input, but no guarantee is given that the final mount option does not fail due to invalid input. - * This holds especially for {@link Builder#setMountFlags(String)}; - */ - interface Builder { - - //TODO: Idea: every setter verifies the set and can throw an IllegalArgumentException - default Builder setMountpoint(Path p) { - throw new UnsupportedOperationException(); - } - - default Builder setOnExitAction(Consumer onExitAction) { - throw new UnsupportedOperationException(); - } - - default Builder setMountFlags(String mountFlags) { - throw new UnsupportedOperationException(); - } - - default Builder setReadOnly(boolean mountReadOnly) { - throw new UnsupportedOperationException(); - } - - FileSystemMount mount() throws MountFailedException; - - } -} diff --git a/src/main/java/org/cryptomator/integrations/mount/FilesystemMountProvider.java b/src/main/java/org/cryptomator/integrations/mount/FilesystemMountProvider.java deleted file mode 100644 index 7e9165f..0000000 --- a/src/main/java/org/cryptomator/integrations/mount/FilesystemMountProvider.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.cryptomator.integrations.mount; - -import org.cryptomator.integrations.common.IntegrationsLoader; - -import java.nio.file.Path; -import java.util.Set; -import java.util.stream.Stream; - -/** - * Vorteile: - * * IoC: Ein Provider weiß was er kann und was nicht! - * * Wegfall der komplizierten Mountpoint Logik - * * App beschränkt sich mehr auf GUI und Logik darum - * * Einfaches ändern/entfernen eines Providers - * * Mounten ist eine Systemintegration! - * * Tests!? - * * Illegal Mount Options Check? - * * In der GUI sieht der Nutzer sofort, was sich ändert. - *

- * Nachteile: - * * Code-Duplikation - * * WebDAV-ServerPort? (-> Legacy Option in Preferences?) - *

- * Ungeklärt: - * * Anzeigen von Fehler dem User (-> Translations nutzbar?) - * * Langfristiger Wechsel zu eigenständigen Prozessen? - */ -public interface FilesystemMountProvider { - - /** - * Loads all supported MountProvider. - * - * @return Stream of supported MountProviders - * @since 1.1.0 - */ - static Stream get() { - return IntegrationsLoader.loadAll(FilesystemMountProvider.class).filter(FilesystemMountProvider::isSupported); - } - - /** - * Name of this provider - * - * @return A human readable name of this provider - */ - String displayName(); - - /** - * Indicates, if this provider can be used. - * - * @return true, if this provider is supported in the current OS environment - */ - boolean isSupported(); - - - /** - * A default mountpoint any filesystem can be mounted to. - * Note, that this method: - *

    - *
  1. method is optional. If not implemented, throws an {@link UnsupportedOperationException}
  2. - *
  3. is not required to serve static content. It should be considerer as a "mount point maker" with the implemetnation as the template engine
  4. - *
- * - * @param mountPointSuffix String used in the generation of a mount point. - * @return A path to a possible mount point. - */ - default Path getDefaultMountPoint(String mountPointSuffix) { - throw new UnsupportedOperationException(); - } - - /** - * Default mount flags. - * Implementation required if feature {@link MountFeature#MOUNT_FLAGS} is supported. - * - * @param mountName Name of the mount in the OS - * @return Concatenated String of valid mount flags - */ - default String getDefaultMountFlags(String mountName) { - throw new UnsupportedOperationException(); - } - - /** - * Mount features supported by this provider. - * - * @return Set of supported {@link MountFeature}s - */ - Set supportedFeatures(); - - - FileSystemMount.Builder forFileSystem(Path fileSystemRoot); - -} diff --git a/src/main/java/org/cryptomator/integrations/mount/Mount.java b/src/main/java/org/cryptomator/integrations/mount/Mount.java new file mode 100644 index 0000000..9a1b375 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/Mount.java @@ -0,0 +1,45 @@ +package org.cryptomator.integrations.mount; + +import java.nio.file.Path; +import java.util.function.Consumer; + +/** + * Handle to control the lifecycle of a mounted file system. + *

+ * Created by {@link MountBuilder} + */ +public interface Mount extends AutoCloseable { + + //TODO: either this or reveal method, not both + Path getAccessPoint(); + + //TODO: is this needed? why not just let the consumer reveal? + // See WebDAV: LinuxGioMounter and LinuxGvfsMounter -> no path, just a command + void reveal(Consumer cmd); + + /** + * Unmounts the mounted Volume. + *

+ * If possible, attempt a graceful unmount. + * + * @throws UnmountFailedException If the unmount was not successful. + * @see #unmountForced() + */ + void unmout() throws UnmountFailedException; + + /** + * If supported, force-unmount the volume. + * + * @throws UnmountFailedException If the unmount was not successful. + * @throws UnsupportedOperationException If {@link MountFeature#UNMOUNT_FORCED} is not supported + */ + default void unmountForced() throws UnmountFailedException { + throw new UnsupportedOperationException(); + } + + default void close() throws UnmountFailedException { + unmout(); + } + + +} diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java new file mode 100644 index 0000000..f968fe8 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -0,0 +1,85 @@ +package org.cryptomator.integrations.mount; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Range; + +import java.nio.file.Path; +import java.util.function.Consumer; + +/** + * Builder to mount a filesystem. + *

+ * The setter may attempt to validate the input, but {@link #mount()} may still fail due to missing or invalid (combination of) options. + * This holds especially for {@link MountBuilder#setMountFlags(String)}; + */ +public interface MountBuilder { + + //TODO: Idea: every setter verifies the set and can throw an IllegalArgumentException + + /** + * Sets the mount point. + * + * @param mountPoint Where to mount the volume + * @return this + * @throws UnsupportedOperationException If {@link MountFeature#MOUNT_POINT_EMPTY_DIR} is not supported // TODO: what MOUNT_POINT_* features do we really need? + * @see MountProvider#getDefaultMountPoint(String) + */ + @Contract("_ -> this") + default MountBuilder setMountpoint(Path mountPoint) { + throw new UnsupportedOperationException(); + } + + // TODO: in what legacy mounter impl is this used? + @Contract("_ -> this") + default MountBuilder setOnExitAction(Consumer onExitAction) { + throw new UnsupportedOperationException(); + } + + /** + * Sets mount flags. + * + * @param mountFlags Mount flags + * @return this + * @throws UnsupportedOperationException If {@link MountFeature#MOUNT_FLAGS} is not supported + * @see MountProvider#getDefaultMountFlags(String) + */ + @Contract("_ -> this") + default MountBuilder setMountFlags(String mountFlags) { + throw new UnsupportedOperationException(); + } + + /** + * Instructs the mount to be read-only. + * + * @param mountReadOnly Whether to mount read-only. + * @return this + * @throws UnsupportedOperationException If {@link MountFeature#READ_ONLY} is not supported + */ + @Contract("_ -> this") + default MountBuilder setReadOnly(boolean mountReadOnly) { + throw new UnsupportedOperationException(); + } + + /** + * Use the given TCP port. + * + * @param port fixed TCP port or 0 to use a system-assigned port + * @return this + * @throws UnsupportedOperationException If {@link MountFeature#PORT} is not supported + */ + @Contract("_ -> this") + default MountBuilder setPort(@Range(from = 0, to = Short.MAX_VALUE) int port) { + throw new UnsupportedOperationException(); + } + + + /** + * Mounts the file system. + * + * @return A mount handle + * @throws MountFailedException If mounting failed + */ + @Contract(" -> new") + Mount mount() throws MountFailedException; + +} diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java index e3d78e2..116ba1e 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java @@ -1,13 +1,39 @@ package org.cryptomator.integrations.mount; +/** + * Describes what aspects of the mount implementation can or should be used. + *

+ * This may be used to show or hide different configuration options depending on the chosen mount provider. + */ public enum MountFeature { + /** + * The provider supports {@link MountProvider#getDefaultMountFlags(String)} + * and the builder requires {@link MountBuilder#setMountFlags(String)}. + */ MOUNT_FLAGS, MOUNT_POINT_EMPTY_DIR, MOUNT_POINT_DRIVE_LETTER, MOUNT_POINT_PATH_PREFIX, + + /** + * The builder supports {@link MountBuilder#setReadOnly(boolean)} + */ READ_ONLY, + + /** + * The mount supports {@link Mount#unmountForced()}. + */ UNMOUNT_FORCED, ON_EXIT_ACTION, + + /** + * The provider supports {@link MountProvider#getDefaultPort()} + * and the builder requires {@link MountBuilder#setPort(int)}. + */ PORT, + + /** + * The provider supports {@link MountProvider#getDefaultMountPoint(String)} + */ DEFAULT_MOUNT_POINT } diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java new file mode 100644 index 0000000..d360a22 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java @@ -0,0 +1,112 @@ +package org.cryptomator.integrations.mount; + +import org.cryptomator.integrations.common.IntegrationsLoader; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.nio.file.Path; +import java.util.Set; +import java.util.stream.Stream; + +// Vorteile: +// * IoC: Ein Provider weiß was er kann und was nicht! +// * Wegfall der komplizierten Mountpoint Logik +// * App beschränkt sich mehr auf GUI und Logik darum +// * Einfaches ändern/entfernen eines Providers +// * Mounten ist eine Systemintegration! +// * Tests!? +// * Illegal Mount Options Check? +// * In der GUI sieht der Nutzer sofort, was sich ändert. +// Nachteile: +// * Code-Duplikation +// * WebDAV-ServerPort? (-> Legacy Option in Preferences?) +// Ungeklärt: +// * Anzeigen von Fehler dem User (-> Translations nutzbar?) +// * Langfristiger Wechsel zu eigenständigen Prozessen? + +/** + * A mechanism to mount a file system. + * + * @since 1.2.0 + */ +public interface MountProvider { + + /** + * Loads all supported mount providers. + * + * @return Stream of supported MountProviders (may be empty) + */ + static Stream get() { + return IntegrationsLoader.loadAll(MountProvider.class).filter(MountProvider::isSupported); + } + + /** + * Name of this provider. + * + * @return A human readable name of this provider + */ + String displayName(); + + /** + * Indicates, if this provider can be used. + * + * @return true, if this provider is supported in the current OS environment + * @implSpec This check needs to return fast and in constant time + */ + boolean isSupported(); + + /** + * A suitable mount point suggested by this provider. + *

+ * Other than caller-provided mount points, the mount point suggested by this method can be + * passed to {@link MountBuilder#setMountpoint(Path)} without further ado. + * + * @param mountPointSuffix String used in the generation of a mount point. + * @return A path to a possible mount point. + * @throws UnsupportedOperationException If {@link MountFeature#DEFAULT_MOUNT_POINT} is not supported + */ + default Path getDefaultMountPoint(String mountPointSuffix) { + throw new UnsupportedOperationException(); + } + + /** + * Default mount flags. May be empty. + * + * @param mountName Name of the mount in the OS + * @return Concatenated String of valid mount flags + * @throws UnsupportedOperationException If {@link MountFeature#MOUNT_FLAGS} is not supported + */ + default String getDefaultMountFlags(String mountName) { + throw new UnsupportedOperationException(); + } + + /** + * The default TCP port used by this provider. + * + * @return fixed TCP port or 0 to use a system-assigned port + * @throws UnsupportedOperationException If {@link MountFeature#PORT} is not supported + */ + @Range(from = 0, to = Short.MAX_VALUE) + default int getDefaultPort() { + throw new UnsupportedOperationException(); + } + + /** + * Mount features supported by this provider. + * + * @return Set of supported {@link MountFeature}s + */ + Set supportedFeatures(); + + + /** + * Creates a new mount builder. + * + * @param fileSystemRoot The root of the VFS to be mounted + * @return New mount builder + */ + @Contract("_ -> new") + MountBuilder forFileSystem(Path fileSystemRoot); + +} From 61f6ca0df18434590007d8c0b52cd71c907b24b3 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 27 Oct 2022 13:49:42 +0200 Subject: [PATCH 09/46] let's assume that there is no mount without a mount point --- .../org/cryptomator/integrations/mount/MountBuilder.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index f968fe8..e5f1ae3 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -21,13 +21,10 @@ public interface MountBuilder { * * @param mountPoint Where to mount the volume * @return this - * @throws UnsupportedOperationException If {@link MountFeature#MOUNT_POINT_EMPTY_DIR} is not supported // TODO: what MOUNT_POINT_* features do we really need? * @see MountProvider#getDefaultMountPoint(String) */ @Contract("_ -> this") - default MountBuilder setMountpoint(Path mountPoint) { - throw new UnsupportedOperationException(); - } + MountBuilder setMountpoint(Path mountPoint); // TODO: in what legacy mounter impl is this used? @Contract("_ -> this") From 8613fb086e386a4f2d7fbf9e71b9d2d4854103ff Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 27 Oct 2022 13:50:03 +0200 Subject: [PATCH 10/46] clarified different requirements to a mount point --- .../integrations/mount/MountFeature.java | 48 +++++++++++++++---- .../integrations/mount/MountProvider.java | 3 +- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java index 116ba1e..99ea635 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java @@ -11,9 +11,40 @@ public enum MountFeature { * and the builder requires {@link MountBuilder#setMountFlags(String)}. */ MOUNT_FLAGS, - MOUNT_POINT_EMPTY_DIR, - MOUNT_POINT_DRIVE_LETTER, - MOUNT_POINT_PATH_PREFIX, + + /** + * With the exception of a provider-supplied default mount point, the mount point must be an existing dir. + *

+ * This option is mutually exclusive with {@link #MOUNT_WITHIN_EXISTING_PARENT}. + * + * @see #DEFAULT_MOUNT_POINT + */ + MOUNT_TO_EXISTING_DIR, + + /** + * With the exception of a provider-supplied default mount point, the mount point must be a non-existing + * child within an existing parent. + *

+ * This option is mutually exclusive with {@link #MOUNT_TO_EXISTING_DIR}. + * + * @see #DEFAULT_MOUNT_POINT + */ + MOUNT_WITHIN_EXISTING_PARENT, + + /** + * The mount point may be a drive letter. + * + * @see #MOUNT_TO_EXISTING_DIR + * @see #MOUNT_WITHIN_EXISTING_PARENT + */ + MOUNT_AS_DRIVE_LETTER, + + /** + * The provider supports suggesting a default mount point via {@link MountProvider#getDefaultMountPoint(String)}. + *

+ * The default mount point is guaranteed to be supported by the mount builder, regardless of its normal restrictions. + */ + DEFAULT_MOUNT_POINT, /** * The builder supports {@link MountBuilder#setReadOnly(boolean)} @@ -24,16 +55,15 @@ public enum MountFeature { * The mount supports {@link Mount#unmountForced()}. */ UNMOUNT_FORCED, - ON_EXIT_ACTION, /** - * The provider supports {@link MountProvider#getDefaultPort()} - * and the builder requires {@link MountBuilder#setPort(int)}. + * The mount supports triggering an event handler, which is somehow triggered at a specific time. // TODO what? */ - PORT, + ON_EXIT_ACTION, /** - * The provider supports {@link MountProvider#getDefaultMountPoint(String)} + * The provider supports {@link MountProvider#getDefaultPort()} + * and the builder requires {@link MountBuilder#setPort(int)}. */ - DEFAULT_MOUNT_POINT + PORT } diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java index d360a22..96d5f1e 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java @@ -60,7 +60,8 @@ static Stream get() { * A suitable mount point suggested by this provider. *

* Other than caller-provided mount points, the mount point suggested by this method can be - * passed to {@link MountBuilder#setMountpoint(Path)} without further ado. + * passed to {@link MountBuilder#setMountpoint(Path)} and is guaranteed to fulfill the builder's requirements + * without further ado. * * @param mountPointSuffix String used in the generation of a mount point. * @return A path to a possible mount point. From 9b76bf8e14afee0af494de6f87c28e6da2c2ec75 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 27 Oct 2022 14:48:25 +0200 Subject: [PATCH 11/46] bump dependencies for JDK 19 support --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f9e3239..ca7bfce 100644 --- a/pom.xml +++ b/pom.xml @@ -59,13 +59,13 @@ org.junit.jupiter junit-jupiter - 5.8.2 + 5.9.0 test org.mockito mockito-core - 4.3.1 + 4.8.0 test From 3a17610cc5e38d8cbfecd253a50ac6083d904760 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 27 Oct 2022 15:45:59 +0200 Subject: [PATCH 12/46] More lean API. Removed features might be readded later: * removed OnExitAction feature * removed reveal() funtion * renamed getAccessPoint() --- .../cryptomator/integrations/mount/Mount.java | 13 ++++++------- .../integrations/mount/MountBuilder.java | 9 --------- .../integrations/mount/MountFeature.java | 5 ----- .../integrations/mount/MountProvider.java | 16 ---------------- 4 files changed, 6 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/Mount.java b/src/main/java/org/cryptomator/integrations/mount/Mount.java index 9a1b375..60ac7b7 100644 --- a/src/main/java/org/cryptomator/integrations/mount/Mount.java +++ b/src/main/java/org/cryptomator/integrations/mount/Mount.java @@ -1,7 +1,6 @@ package org.cryptomator.integrations.mount; import java.nio.file.Path; -import java.util.function.Consumer; /** * Handle to control the lifecycle of a mounted file system. @@ -10,12 +9,12 @@ */ public interface Mount extends AutoCloseable { - //TODO: either this or reveal method, not both - Path getAccessPoint(); - - //TODO: is this needed? why not just let the consumer reveal? - // See WebDAV: LinuxGioMounter and LinuxGvfsMounter -> no path, just a command - void reveal(Consumer cmd); + /** + * Returns the absolute OS path, where this mount can be accessed. + * + * @return Absolute path to the mountpoint. + */ + Path getMountpoint(); /** * Unmounts the mounted Volume. diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index e5f1ae3..eb61741 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -4,7 +4,6 @@ import org.jetbrains.annotations.Range; import java.nio.file.Path; -import java.util.function.Consumer; /** * Builder to mount a filesystem. @@ -14,8 +13,6 @@ */ public interface MountBuilder { - //TODO: Idea: every setter verifies the set and can throw an IllegalArgumentException - /** * Sets the mount point. * @@ -26,12 +23,6 @@ public interface MountBuilder { @Contract("_ -> this") MountBuilder setMountpoint(Path mountPoint); - // TODO: in what legacy mounter impl is this used? - @Contract("_ -> this") - default MountBuilder setOnExitAction(Consumer onExitAction) { - throw new UnsupportedOperationException(); - } - /** * Sets mount flags. * diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java index 99ea635..9bd960f 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java @@ -56,11 +56,6 @@ public enum MountFeature { */ UNMOUNT_FORCED, - /** - * The mount supports triggering an event handler, which is somehow triggered at a specific time. // TODO what? - */ - ON_EXIT_ACTION, - /** * The provider supports {@link MountProvider#getDefaultPort()} * and the builder requires {@link MountBuilder#setPort(int)}. diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java index 96d5f1e..6365560 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java @@ -9,22 +9,6 @@ import java.util.Set; import java.util.stream.Stream; -// Vorteile: -// * IoC: Ein Provider weiß was er kann und was nicht! -// * Wegfall der komplizierten Mountpoint Logik -// * App beschränkt sich mehr auf GUI und Logik darum -// * Einfaches ändern/entfernen eines Providers -// * Mounten ist eine Systemintegration! -// * Tests!? -// * Illegal Mount Options Check? -// * In der GUI sieht der Nutzer sofort, was sich ändert. -// Nachteile: -// * Code-Duplikation -// * WebDAV-ServerPort? (-> Legacy Option in Preferences?) -// Ungeklärt: -// * Anzeigen von Fehler dem User (-> Translations nutzbar?) -// * Langfristiger Wechsel zu eigenständigen Prozessen? - /** * A mechanism to mount a file system. * From 703f5bfc77caf20fdea0ce5b4b15e1f1bdf733d8 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 27 Oct 2022 16:10:58 +0200 Subject: [PATCH 13/46] Mark API as experimental --- .../org/cryptomator/integrations/mount/package-info.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/org/cryptomator/integrations/mount/package-info.java diff --git a/src/main/java/org/cryptomator/integrations/mount/package-info.java b/src/main/java/org/cryptomator/integrations/mount/package-info.java new file mode 100644 index 0000000..d6535b2 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/package-info.java @@ -0,0 +1,7 @@ +/** + * Mount service package + */ +@ApiStatus.Experimental +package org.cryptomator.integrations.mount; + +import org.jetbrains.annotations.ApiStatus; From 41ff2b4cd73f3b42ec465e784019b03ddaacc8eb Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 27 Oct 2022 16:16:39 +0200 Subject: [PATCH 14/46] prepare 1.2.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ca7bfce..34d6dbd 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.cryptomator integrations-api - 1.2.0-SNAPSHOT + 1.2.0 Cryptomator Integrations API Defines optional service interfaces that may be used by Cryptomator From 19048c4cadfd3475813ac8a061ed61295d4cdf6e Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 31 Oct 2022 13:13:25 +0100 Subject: [PATCH 15/46] typo [ci skip] --- src/main/java/org/cryptomator/integrations/mount/Mount.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/Mount.java b/src/main/java/org/cryptomator/integrations/mount/Mount.java index 60ac7b7..6a529b7 100644 --- a/src/main/java/org/cryptomator/integrations/mount/Mount.java +++ b/src/main/java/org/cryptomator/integrations/mount/Mount.java @@ -24,7 +24,7 @@ public interface Mount extends AutoCloseable { * @throws UnmountFailedException If the unmount was not successful. * @see #unmountForced() */ - void unmout() throws UnmountFailedException; + void unmount() throws UnmountFailedException; /** * If supported, force-unmount the volume. @@ -37,7 +37,7 @@ default void unmountForced() throws UnmountFailedException { } default void close() throws UnmountFailedException { - unmout(); + unmount(); } From 72ae4b39862e3fcd31dfac70a9e8eabbe901c55a Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 1 Nov 2022 10:25:26 +0100 Subject: [PATCH 16/46] - DEFAULT_MOUNT_POINT + MOUNT_TO_SYSTEM_CHOSEN_PATH + VOLUME_ID --- .../integrations/mount/MountBuilder.java | 28 ++++++++++++++----- .../integrations/mount/MountFeature.java | 26 ++++++++++------- .../integrations/mount/MountProvider.java | 25 +++++++---------- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index eb61741..2fc2864 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -15,13 +15,16 @@ public interface MountBuilder { /** * Sets the mount point. + *

+ * Unless the mount provide supports {@link MountFeature#MOUNT_TO_SYSTEM_CHOSEN_PATH}, setting a mount point is required. * * @param mountPoint Where to mount the volume * @return this - * @see MountProvider#getDefaultMountPoint(String) */ @Contract("_ -> this") - MountBuilder setMountpoint(Path mountPoint); + default MountBuilder setMountpoint(Path mountPoint) { + throw new UnsupportedOperationException(); + } /** * Sets mount flags. @@ -36,6 +39,18 @@ default MountBuilder setMountFlags(String mountFlags) { throw new UnsupportedOperationException(); } + /** + * Use the given TCP port. + * + * @param port Fixed TCP port or 0 to use a system-assigned port + * @return this + * @throws UnsupportedOperationException If {@link MountFeature#PORT} is not supported + */ + @Contract("_ -> this") + default MountBuilder setPort(@Range(from = 0, to = Short.MAX_VALUE) int port) { + throw new UnsupportedOperationException(); + } + /** * Instructs the mount to be read-only. * @@ -49,18 +64,17 @@ default MountBuilder setReadOnly(boolean mountReadOnly) { } /** - * Use the given TCP port. + * Sets a unique volume id. * - * @param port fixed TCP port or 0 to use a system-assigned port + * @param volumeId Volume id * @return this - * @throws UnsupportedOperationException If {@link MountFeature#PORT} is not supported + * @throws UnsupportedOperationException If {@link MountFeature#VOLUME_ID} is not supported */ @Contract("_ -> this") - default MountBuilder setPort(@Range(from = 0, to = Short.MAX_VALUE) int port) { + default MountBuilder setVolumeId(String volumeId) { throw new UnsupportedOperationException(); } - /** * Mounts the file system. * diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java index 9bd960f..7b0d5c1 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java @@ -1,5 +1,7 @@ package org.cryptomator.integrations.mount; +import java.nio.file.Path; + /** * Describes what aspects of the mount implementation can or should be used. *

@@ -17,7 +19,7 @@ public enum MountFeature { *

* This option is mutually exclusive with {@link #MOUNT_WITHIN_EXISTING_PARENT}. * - * @see #DEFAULT_MOUNT_POINT + * @see #MOUNT_TO_SYSTEM_CHOSEN_PATH */ MOUNT_TO_EXISTING_DIR, @@ -27,7 +29,7 @@ public enum MountFeature { *

* This option is mutually exclusive with {@link #MOUNT_TO_EXISTING_DIR}. * - * @see #DEFAULT_MOUNT_POINT + * @see #MOUNT_TO_SYSTEM_CHOSEN_PATH */ MOUNT_WITHIN_EXISTING_PARENT, @@ -36,18 +38,23 @@ public enum MountFeature { * * @see #MOUNT_TO_EXISTING_DIR * @see #MOUNT_WITHIN_EXISTING_PARENT + * @see #MOUNT_TO_SYSTEM_CHOSEN_PATH */ MOUNT_AS_DRIVE_LETTER, /** - * The provider supports suggesting a default mount point via {@link MountProvider#getDefaultMountPoint(String)}. - *

- * The default mount point is guaranteed to be supported by the mount builder, regardless of its normal restrictions. + * The provider supports suggesting a default mount point, if no mount point is set via {@link MountBuilder#setMountpoint(Path)}. */ - DEFAULT_MOUNT_POINT, + MOUNT_TO_SYSTEM_CHOSEN_PATH, /** - * The builder supports {@link MountBuilder#setReadOnly(boolean)} + * The provider supports {@link MountProvider#getDefaultPort()} + * and the builder requires {@link MountBuilder#setPort(int)}. + */ + PORT, + + /** + * The builder supports {@link MountBuilder#setReadOnly(boolean)}. */ READ_ONLY, @@ -57,8 +64,7 @@ public enum MountFeature { UNMOUNT_FORCED, /** - * The provider supports {@link MountProvider#getDefaultPort()} - * and the builder requires {@link MountBuilder#setPort(int)}. + * The builder requires {@link MountBuilder#setVolumeId(String)}. */ - PORT + VOLUME_ID } diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java index 6365560..939688f 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java @@ -40,21 +40,6 @@ static Stream get() { */ boolean isSupported(); - /** - * A suitable mount point suggested by this provider. - *

- * Other than caller-provided mount points, the mount point suggested by this method can be - * passed to {@link MountBuilder#setMountpoint(Path)} and is guaranteed to fulfill the builder's requirements - * without further ado. - * - * @param mountPointSuffix String used in the generation of a mount point. - * @return A path to a possible mount point. - * @throws UnsupportedOperationException If {@link MountFeature#DEFAULT_MOUNT_POINT} is not supported - */ - default Path getDefaultMountPoint(String mountPointSuffix) { - throw new UnsupportedOperationException(); - } - /** * Default mount flags. May be empty. * @@ -84,6 +69,16 @@ default int getDefaultPort() { */ Set supportedFeatures(); + /** + * Tests whether this provider supports the given feature. + * + * @param feature The feature + * @return {@code true} if supported + */ + default boolean supportsFeature(MountFeature feature) { + return supportedFeatures().contains(feature); + } + /** * Creates a new mount builder. From 4141ec848e0f1698f34e7733b5776037f8bb52bc Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 4 Nov 2022 12:17:38 +0100 Subject: [PATCH 17/46] Rename MountFeature.PORT to LOOPBACK_PORT and adjust related methods --- .../integrations/mount/MountBuilder.java | 23 ++++++++++--------- .../integrations/mount/MountFeature.java | 12 +++++----- .../integrations/mount/MountProvider.java | 7 +++--- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index 2fc2864..a96fa8c 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -13,6 +13,18 @@ */ public interface MountBuilder { + /** + * Use the given TCP port of the loopback address. + * + * @param port Fixed TCP port or 0 to use a system-assigned port + * @return this + * @throws UnsupportedOperationException If {@link MountFeature#LOOPBACK_PORT} is not supported + */ + @Contract("_ -> this") + default MountBuilder setLoopbackPort(@Range(from = 0, to = Short.MAX_VALUE) int port) { + throw new UnsupportedOperationException(); + } + /** * Sets the mount point. *

@@ -39,17 +51,6 @@ default MountBuilder setMountFlags(String mountFlags) { throw new UnsupportedOperationException(); } - /** - * Use the given TCP port. - * - * @param port Fixed TCP port or 0 to use a system-assigned port - * @return this - * @throws UnsupportedOperationException If {@link MountFeature#PORT} is not supported - */ - @Contract("_ -> this") - default MountBuilder setPort(@Range(from = 0, to = Short.MAX_VALUE) int port) { - throw new UnsupportedOperationException(); - } /** * Instructs the mount to be read-only. diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java index 7b0d5c1..1fc5223 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java @@ -8,6 +8,12 @@ * This may be used to show or hide different configuration options depending on the chosen mount provider. */ public enum MountFeature { + /** + * The provider supports {@link MountProvider#getDefaultLoopbackPort()} + * and the builder requires {@link MountBuilder#setLoopbackPort(int)}. + */ + LOOPBACK_PORT, + /** * The provider supports {@link MountProvider#getDefaultMountFlags(String)} * and the builder requires {@link MountBuilder#setMountFlags(String)}. @@ -47,12 +53,6 @@ public enum MountFeature { */ MOUNT_TO_SYSTEM_CHOSEN_PATH, - /** - * The provider supports {@link MountProvider#getDefaultPort()} - * and the builder requires {@link MountBuilder#setPort(int)}. - */ - PORT, - /** * The builder supports {@link MountBuilder#setReadOnly(boolean)}. */ diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java index 939688f..86c737f 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountProvider.java @@ -2,7 +2,6 @@ import org.cryptomator.integrations.common.IntegrationsLoader; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Range; import java.nio.file.Path; @@ -52,13 +51,13 @@ default String getDefaultMountFlags(String mountName) { } /** - * The default TCP port used by this provider. + * The default TCP port of the loopback address used by this provider. * * @return fixed TCP port or 0 to use a system-assigned port - * @throws UnsupportedOperationException If {@link MountFeature#PORT} is not supported + * @throws UnsupportedOperationException If {@link MountFeature#LOOPBACK_PORT} is not supported */ @Range(from = 0, to = Short.MAX_VALUE) - default int getDefaultPort() { + default int getDefaultLoopbackPort() { throw new UnsupportedOperationException(); } From 9d53958450ace74f024a3124c92ce48ee2911667 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 4 Nov 2022 12:25:26 +0100 Subject: [PATCH 18/46] Add MountFeature.LOOPBACK_HOST_NAME --- .../cryptomator/integrations/mount/MountBuilder.java | 12 ++++++++++++ .../cryptomator/integrations/mount/MountFeature.java | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index a96fa8c..f254a71 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -13,6 +13,18 @@ */ public interface MountBuilder { + /** + * Use the given host name as the loopback address. + * + * @param hostName string conforming with the uri host part + * @return this + * @throws UnsupportedOperationException If {@link MountFeature#LOOPBACK_HOST_NAME} is not supported + */ + @Contract("_ -> this") + default MountBuilder setLoopbackHostName(String hostName) { + throw new UnsupportedOperationException(); + } + /** * Use the given TCP port of the loopback address. * diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java index 1fc5223..46ad3cd 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java @@ -8,6 +8,11 @@ * This may be used to show or hide different configuration options depending on the chosen mount provider. */ public enum MountFeature { + /** + * The builder supports {@link MountBuilder#setLoopbackHostName(String)}. + */ + LOOPBACK_HOST_NAME, + /** * The provider supports {@link MountProvider#getDefaultLoopbackPort()} * and the builder requires {@link MountBuilder#setLoopbackPort(int)}. From a00a7fadae546288b9e2ca003976252319c1c464 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 4 Nov 2022 12:28:43 +0100 Subject: [PATCH 19/46] Correct naming of mount spi: MountProvider is the _service_ interface --- src/main/java/module-info.java | 4 ++-- .../org/cryptomator/integrations/mount/MountBuilder.java | 2 +- .../org/cryptomator/integrations/mount/MountFeature.java | 4 ++-- .../mount/{MountProvider.java => MountService.java} | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) rename src/main/java/org/cryptomator/integrations/mount/{MountProvider.java => MountService.java} (92%) diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index cddd5d0..492b484 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,4 +1,4 @@ -import org.cryptomator.integrations.mount.MountProvider; +import org.cryptomator.integrations.mount.MountService; import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.keychain.KeychainAccessProvider; @@ -19,7 +19,7 @@ uses AutoStartProvider; uses KeychainAccessProvider; - uses MountProvider; + uses MountService; uses TrayIntegrationProvider; uses TrayMenuController; uses UiAppearanceProvider; diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index f254a71..c57408f 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -56,7 +56,7 @@ default MountBuilder setMountpoint(Path mountPoint) { * @param mountFlags Mount flags * @return this * @throws UnsupportedOperationException If {@link MountFeature#MOUNT_FLAGS} is not supported - * @see MountProvider#getDefaultMountFlags(String) + * @see MountService#getDefaultMountFlags(String) */ @Contract("_ -> this") default MountBuilder setMountFlags(String mountFlags) { diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java index 46ad3cd..d69bd50 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountFeature.java @@ -14,13 +14,13 @@ public enum MountFeature { LOOPBACK_HOST_NAME, /** - * The provider supports {@link MountProvider#getDefaultLoopbackPort()} + * The provider supports {@link MountService#getDefaultLoopbackPort()} * and the builder requires {@link MountBuilder#setLoopbackPort(int)}. */ LOOPBACK_PORT, /** - * The provider supports {@link MountProvider#getDefaultMountFlags(String)} + * The provider supports {@link MountService#getDefaultMountFlags(String)} * and the builder requires {@link MountBuilder#setMountFlags(String)}. */ MOUNT_FLAGS, diff --git a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java b/src/main/java/org/cryptomator/integrations/mount/MountService.java similarity index 92% rename from src/main/java/org/cryptomator/integrations/mount/MountProvider.java rename to src/main/java/org/cryptomator/integrations/mount/MountService.java index 86c737f..9f678f8 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountProvider.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountService.java @@ -13,15 +13,15 @@ * * @since 1.2.0 */ -public interface MountProvider { +public interface MountService { /** * Loads all supported mount providers. * * @return Stream of supported MountProviders (may be empty) */ - static Stream get() { - return IntegrationsLoader.loadAll(MountProvider.class).filter(MountProvider::isSupported); + static Stream get() { + return IntegrationsLoader.loadAll(MountService.class).filter(MountService::isSupported); } /** From e4f475abcb85cc1b4c5a3cfa8649ef58264ed632 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 4 Nov 2022 12:32:33 +0100 Subject: [PATCH 20/46] Add more documentation to feature VOLUME_ID --- .../java/org/cryptomator/integrations/mount/MountBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index c57408f..d14d6b6 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -79,7 +79,7 @@ default MountBuilder setReadOnly(boolean mountReadOnly) { /** * Sets a unique volume id. * - * @param volumeId Volume id + * @param volumeId String conforming with the os-dependent path component restrictions * @return this * @throws UnsupportedOperationException If {@link MountFeature#VOLUME_ID} is not supported */ From 4922845fa55cce01247e041d53d2442cf2dae616 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 4 Nov 2022 12:34:10 +0100 Subject: [PATCH 21/46] Rename MountFeature to MountCapability --- .../org/cryptomator/integrations/mount/Mount.java | 2 +- .../cryptomator/integrations/mount/MountBuilder.java | 12 ++++++------ .../{MountFeature.java => MountCapability.java} | 2 +- .../cryptomator/integrations/mount/MountService.java | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) rename src/main/java/org/cryptomator/integrations/mount/{MountFeature.java => MountCapability.java} (98%) diff --git a/src/main/java/org/cryptomator/integrations/mount/Mount.java b/src/main/java/org/cryptomator/integrations/mount/Mount.java index 6a529b7..3f01d96 100644 --- a/src/main/java/org/cryptomator/integrations/mount/Mount.java +++ b/src/main/java/org/cryptomator/integrations/mount/Mount.java @@ -30,7 +30,7 @@ public interface Mount extends AutoCloseable { * If supported, force-unmount the volume. * * @throws UnmountFailedException If the unmount was not successful. - * @throws UnsupportedOperationException If {@link MountFeature#UNMOUNT_FORCED} is not supported + * @throws UnsupportedOperationException If {@link MountCapability#UNMOUNT_FORCED} is not supported */ default void unmountForced() throws UnmountFailedException { throw new UnsupportedOperationException(); diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index d14d6b6..8f3d0e9 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -18,7 +18,7 @@ public interface MountBuilder { * * @param hostName string conforming with the uri host part * @return this - * @throws UnsupportedOperationException If {@link MountFeature#LOOPBACK_HOST_NAME} is not supported + * @throws UnsupportedOperationException If {@link MountCapability#LOOPBACK_HOST_NAME} is not supported */ @Contract("_ -> this") default MountBuilder setLoopbackHostName(String hostName) { @@ -30,7 +30,7 @@ default MountBuilder setLoopbackHostName(String hostName) { * * @param port Fixed TCP port or 0 to use a system-assigned port * @return this - * @throws UnsupportedOperationException If {@link MountFeature#LOOPBACK_PORT} is not supported + * @throws UnsupportedOperationException If {@link MountCapability#LOOPBACK_PORT} is not supported */ @Contract("_ -> this") default MountBuilder setLoopbackPort(@Range(from = 0, to = Short.MAX_VALUE) int port) { @@ -40,7 +40,7 @@ default MountBuilder setLoopbackPort(@Range(from = 0, to = Short.MAX_VALUE) int /** * Sets the mount point. *

- * Unless the mount provide supports {@link MountFeature#MOUNT_TO_SYSTEM_CHOSEN_PATH}, setting a mount point is required. + * Unless the mount provide supports {@link MountCapability#MOUNT_TO_SYSTEM_CHOSEN_PATH}, setting a mount point is required. * * @param mountPoint Where to mount the volume * @return this @@ -55,7 +55,7 @@ default MountBuilder setMountpoint(Path mountPoint) { * * @param mountFlags Mount flags * @return this - * @throws UnsupportedOperationException If {@link MountFeature#MOUNT_FLAGS} is not supported + * @throws UnsupportedOperationException If {@link MountCapability#MOUNT_FLAGS} is not supported * @see MountService#getDefaultMountFlags(String) */ @Contract("_ -> this") @@ -69,7 +69,7 @@ default MountBuilder setMountFlags(String mountFlags) { * * @param mountReadOnly Whether to mount read-only. * @return this - * @throws UnsupportedOperationException If {@link MountFeature#READ_ONLY} is not supported + * @throws UnsupportedOperationException If {@link MountCapability#READ_ONLY} is not supported */ @Contract("_ -> this") default MountBuilder setReadOnly(boolean mountReadOnly) { @@ -81,7 +81,7 @@ default MountBuilder setReadOnly(boolean mountReadOnly) { * * @param volumeId String conforming with the os-dependent path component restrictions * @return this - * @throws UnsupportedOperationException If {@link MountFeature#VOLUME_ID} is not supported + * @throws UnsupportedOperationException If {@link MountCapability#VOLUME_ID} is not supported */ @Contract("_ -> this") default MountBuilder setVolumeId(String volumeId) { diff --git a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java similarity index 98% rename from src/main/java/org/cryptomator/integrations/mount/MountFeature.java rename to src/main/java/org/cryptomator/integrations/mount/MountCapability.java index d69bd50..dc1d42b 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountFeature.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java @@ -7,7 +7,7 @@ *

* This may be used to show or hide different configuration options depending on the chosen mount provider. */ -public enum MountFeature { +public enum MountCapability { /** * The builder supports {@link MountBuilder#setLoopbackHostName(String)}. */ diff --git a/src/main/java/org/cryptomator/integrations/mount/MountService.java b/src/main/java/org/cryptomator/integrations/mount/MountService.java index 9f678f8..b6d4731 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountService.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountService.java @@ -44,7 +44,7 @@ static Stream get() { * * @param mountName Name of the mount in the OS * @return Concatenated String of valid mount flags - * @throws UnsupportedOperationException If {@link MountFeature#MOUNT_FLAGS} is not supported + * @throws UnsupportedOperationException If {@link MountCapability#MOUNT_FLAGS} is not supported */ default String getDefaultMountFlags(String mountName) { throw new UnsupportedOperationException(); @@ -54,7 +54,7 @@ default String getDefaultMountFlags(String mountName) { * The default TCP port of the loopback address used by this provider. * * @return fixed TCP port or 0 to use a system-assigned port - * @throws UnsupportedOperationException If {@link MountFeature#LOOPBACK_PORT} is not supported + * @throws UnsupportedOperationException If {@link MountCapability#LOOPBACK_PORT} is not supported */ @Range(from = 0, to = Short.MAX_VALUE) default int getDefaultLoopbackPort() { @@ -64,9 +64,9 @@ default int getDefaultLoopbackPort() { /** * Mount features supported by this provider. * - * @return Set of supported {@link MountFeature}s + * @return Set of supported {@link MountCapability}s */ - Set supportedFeatures(); + Set supportedFeatures(); /** * Tests whether this provider supports the given feature. @@ -74,7 +74,7 @@ default int getDefaultLoopbackPort() { * @param feature The feature * @return {@code true} if supported */ - default boolean supportsFeature(MountFeature feature) { + default boolean supportsFeature(MountCapability feature) { return supportedFeatures().contains(feature); } From 6f6c6a5c7254ea8cc3aaf976ae850f01fa4a0987 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 4 Nov 2022 12:58:28 +0100 Subject: [PATCH 22/46] Finish renaming from 4922845fa55cce01247e041d53d2442cf2dae616 --- .../cryptomator/integrations/mount/MountService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountService.java b/src/main/java/org/cryptomator/integrations/mount/MountService.java index b6d4731..9b8bf7e 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountService.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountService.java @@ -62,20 +62,20 @@ default int getDefaultLoopbackPort() { } /** - * Mount features supported by this provider. + * Mount capabilites supported by this provider. * * @return Set of supported {@link MountCapability}s */ - Set supportedFeatures(); + Set capabilities(); /** - * Tests whether this provider supports the given feature. + * Tests whether this provider supports the given capability. * - * @param feature The feature + * @param capability The capability * @return {@code true} if supported */ - default boolean supportsFeature(MountCapability feature) { - return supportedFeatures().contains(feature); + default boolean supportsCapability(MountCapability capability) { + return capabilities().contains(capability); } From 6be34137ccc2a5dd0f5c5d07e28b4085c68b1af4 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Nov 2022 08:39:49 +0100 Subject: [PATCH 23/46] allow path- and uri-based mount points --- .../cryptomator/integrations/mount/Mount.java | 4 +-- .../integrations/mount/Mountpoint.java | 36 +++++++++++++++++++ .../integrations/mount/MountpointTest.java | 36 +++++++++++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/cryptomator/integrations/mount/Mountpoint.java create mode 100644 src/test/java/org/cryptomator/integrations/mount/MountpointTest.java diff --git a/src/main/java/org/cryptomator/integrations/mount/Mount.java b/src/main/java/org/cryptomator/integrations/mount/Mount.java index 3f01d96..266dd5e 100644 --- a/src/main/java/org/cryptomator/integrations/mount/Mount.java +++ b/src/main/java/org/cryptomator/integrations/mount/Mount.java @@ -1,7 +1,5 @@ package org.cryptomator.integrations.mount; -import java.nio.file.Path; - /** * Handle to control the lifecycle of a mounted file system. *

@@ -14,7 +12,7 @@ public interface Mount extends AutoCloseable { * * @return Absolute path to the mountpoint. */ - Path getMountpoint(); + Mountpoint getMountpoint(); /** * Unmounts the mounted Volume. diff --git a/src/main/java/org/cryptomator/integrations/mount/Mountpoint.java b/src/main/java/org/cryptomator/integrations/mount/Mountpoint.java new file mode 100644 index 0000000..91f61ea --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/mount/Mountpoint.java @@ -0,0 +1,36 @@ +package org.cryptomator.integrations.mount; + +import java.net.URI; +import java.nio.file.Path; + +/** + * A {@link Mount}'s mount point. There are two types of mount points: Path-based and URI-based. + */ +public sealed interface Mountpoint permits Mountpoint.WithPath, Mountpoint.WithUri { + + /** + * Gets an URI representation of this mount point. + * + * @return an URI pointing to this mount point + */ + URI uri(); + + static Mountpoint forUri(URI uri) { + return new WithUri(uri); + } + + static Mountpoint forPath(Path path) { + return new WithPath(path); + } + + record WithUri(URI uri) implements Mountpoint { + } + + record WithPath(Path path) implements Mountpoint { + + public URI uri() { + return path.toUri(); + } + + } +} diff --git a/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java b/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java new file mode 100644 index 0000000..7a123a3 --- /dev/null +++ b/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java @@ -0,0 +1,36 @@ +package org.cryptomator.integrations.mount; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.net.URI; +import java.nio.file.Path; + +public class MountpointTest { + + @Test + @DisplayName("MountPoint.forPath()") + public void testForPath() { + var path = Path.of("/foo/bar"); + var mountPoint = Mountpoint.forPath(path); + + if (mountPoint instanceof Mountpoint.WithPath m) { + Assertions.assertEquals(path, m.path()); + Assertions.assertEquals(URI.create("file:/foo/bar"), mountPoint.uri()); + } else { + Assertions.fail(); + } + } + + @Test + @DisplayName("MountPoint.forUri()") + public void testForUri() { + var uri = URI.create("webdav://localhost:8080/foo/bar"); + var mountPoint = Mountpoint.forUri(uri); + + Assertions.assertTrue(mountPoint instanceof Mountpoint.WithUri); + Assertions.assertEquals(uri, mountPoint.uri()); + } + +} \ No newline at end of file From 3358f2da308b62d6287809e226c6288b95b54a88 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Nov 2022 08:42:32 +0100 Subject: [PATCH 24/46] renamed method --- .../java/org/cryptomator/integrations/mount/MountService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountService.java b/src/main/java/org/cryptomator/integrations/mount/MountService.java index 9b8bf7e..0bf5edd 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountService.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountService.java @@ -74,7 +74,7 @@ default int getDefaultLoopbackPort() { * @param capability The capability * @return {@code true} if supported */ - default boolean supportsCapability(MountCapability capability) { + default boolean hasCapability(MountCapability capability) { return capabilities().contains(capability); } From 60e32c59d36012faae3d8e6a7e09b10310c1d8cc Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 5 Nov 2022 08:45:49 +0100 Subject: [PATCH 25/46] Allow throwing IOExceptions during Mount.close() --- .../java/org/cryptomator/integrations/mount/Mount.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/Mount.java b/src/main/java/org/cryptomator/integrations/mount/Mount.java index 266dd5e..24754d9 100644 --- a/src/main/java/org/cryptomator/integrations/mount/Mount.java +++ b/src/main/java/org/cryptomator/integrations/mount/Mount.java @@ -1,5 +1,7 @@ package org.cryptomator.integrations.mount; +import java.io.IOException; + /** * Handle to control the lifecycle of a mounted file system. *

@@ -34,7 +36,13 @@ default void unmountForced() throws UnmountFailedException { throw new UnsupportedOperationException(); } - default void close() throws UnmountFailedException { + /** + * Unmounts (if required) and releases any resources. + * + * @throws UnmountFailedException Thrown if unmounting failed + * @throws IOException Thrown if cleaning up resources failed + */ + default void close() throws UnmountFailedException, IOException { unmount(); } From ab2868ef7c8770e9401b50b2f0b6dbd793c47bec Mon Sep 17 00:00:00 2001 From: Edward Chow Date: Mon, 7 Nov 2022 04:20:55 +1100 Subject: [PATCH 26/46] add `onBeforeOpenMenu` listener to TrayMenuController (#11) --- .../integrations/tray/TrayMenuController.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java index 2d8b864..63edf14 100644 --- a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java @@ -40,4 +40,16 @@ static Optional get() { */ void updateTrayMenu(List items) throws TrayMenuException; + /** + * Action to run before the tray menu opens. + *

+ * This method is used to set up an event listener for when the menu is opened, + * e.g. so that the vault list can be updated to reflect volume mount state changes + * which occur while Cryptomator is in the system tray (and not open). + * + * @param listener + * @throws IllegalStateException thrown when adding listeners fails (i.e. there's no tray menu) + */ + void onBeforeOpenMenu(Runnable listener); + } From 945177b613ea8e7818ce9efe41c62d98c86593af Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 8 Nov 2022 16:27:57 +0100 Subject: [PATCH 27/46] Remove parameters from method `getDefaultMountFlags` --- .../java/org/cryptomator/integrations/mount/MountBuilder.java | 2 +- .../org/cryptomator/integrations/mount/MountCapability.java | 2 +- .../java/org/cryptomator/integrations/mount/MountService.java | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index 8f3d0e9..6892383 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -56,7 +56,7 @@ default MountBuilder setMountpoint(Path mountPoint) { * @param mountFlags Mount flags * @return this * @throws UnsupportedOperationException If {@link MountCapability#MOUNT_FLAGS} is not supported - * @see MountService#getDefaultMountFlags(String) + * @see MountService#getDefaultMountFlags() */ @Contract("_ -> this") default MountBuilder setMountFlags(String mountFlags) { diff --git a/src/main/java/org/cryptomator/integrations/mount/MountCapability.java b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java index dc1d42b..f95a966 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountCapability.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java @@ -20,7 +20,7 @@ public enum MountCapability { LOOPBACK_PORT, /** - * The provider supports {@link MountService#getDefaultMountFlags(String)} + * The service provider supports {@link MountService#getDefaultMountFlags()} * and the builder requires {@link MountBuilder#setMountFlags(String)}. */ MOUNT_FLAGS, diff --git a/src/main/java/org/cryptomator/integrations/mount/MountService.java b/src/main/java/org/cryptomator/integrations/mount/MountService.java index 0bf5edd..207f30e 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountService.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountService.java @@ -42,11 +42,10 @@ static Stream get() { /** * Default mount flags. May be empty. * - * @param mountName Name of the mount in the OS * @return Concatenated String of valid mount flags * @throws UnsupportedOperationException If {@link MountCapability#MOUNT_FLAGS} is not supported */ - default String getDefaultMountFlags(String mountName) { + default String getDefaultMountFlags() { throw new UnsupportedOperationException(); } From fdc2ba72dbc14fdf9a900a6997f3714420cdb0a1 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 8 Nov 2022 16:28:48 +0100 Subject: [PATCH 28/46] Add capability VOLUME_NAME --- .../integrations/mount/MountBuilder.java | 16 ++++++++++++++++ .../integrations/mount/MountCapability.java | 7 ++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index 6892383..e7fffe2 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -78,6 +78,8 @@ default MountBuilder setReadOnly(boolean mountReadOnly) { /** * Sets a unique volume id. + *

+ * The volume id is used as a path component, thus must conform with the os-dependent path component restrictions. * * @param volumeId String conforming with the os-dependent path component restrictions * @return this @@ -88,6 +90,20 @@ default MountBuilder setVolumeId(String volumeId) { throw new UnsupportedOperationException(); } + /** + * Sets a volume name. + *

+ * The volume name is intended to be human-readable. The input string might be altered to replace non-conforming characters and thus is not suited to identify the volume. + * + * @param volumeName String conforming with the os-dependent naming restrictions + * @return this + * @throws UnsupportedOperationException If {@link MountCapability#VOLUME_ID} is not supported + */ + @Contract("_ -> this") + default MountBuilder setVolumeName(String volumeName) { + throw new UnsupportedOperationException(); + } + /** * Mounts the file system. * diff --git a/src/main/java/org/cryptomator/integrations/mount/MountCapability.java b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java index f95a966..c837e84 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountCapability.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java @@ -71,5 +71,10 @@ public enum MountCapability { /** * The builder requires {@link MountBuilder#setVolumeId(String)}. */ - VOLUME_ID + VOLUME_ID, + + /** + * The builder supports {@link MountBuilder#setVolumeName(String)}. + */ + VOLUME_NAME } From d3469bf302fd6be8be60174fa930be4f5e4ee7b2 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 8 Nov 2022 16:34:09 +0100 Subject: [PATCH 29/46] add capability FILE_SYSTEM_NAME --- .../cryptomator/integrations/mount/MountBuilder.java | 12 ++++++++++++ .../integrations/mount/MountCapability.java | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index e7fffe2..d6afc9a 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -13,6 +13,18 @@ */ public interface MountBuilder { + /** + * Sets the file system name. + * + * @param fileSystemName file system name + * @return this + * @throws UnsupportedOperationException If {@link MountCapability#FILE_SYSTEM_NAME} is not supported + */ + @Contract("_ -> this") + default MountBuilder setFileSystemName(String fileSystemName) { + throw new UnsupportedOperationException(); + } + /** * Use the given host name as the loopback address. * diff --git a/src/main/java/org/cryptomator/integrations/mount/MountCapability.java b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java index c837e84..2b4a4cb 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountCapability.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java @@ -8,13 +8,18 @@ * This may be used to show or hide different configuration options depending on the chosen mount provider. */ public enum MountCapability { + /** + * The builder supports {@link MountBuilder#setFileSystemName(String)}. + */ + FILE_SYSTEM_NAME, + /** * The builder supports {@link MountBuilder#setLoopbackHostName(String)}. */ LOOPBACK_HOST_NAME, /** - * The provider supports {@link MountService#getDefaultLoopbackPort()} + * The service provider supports {@link MountService#getDefaultLoopbackPort()} * and the builder requires {@link MountBuilder#setLoopbackPort(int)}. */ LOOPBACK_PORT, From 040bcced736c0b8f55b0724c107e5da6e51fd891 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 8 Nov 2022 16:34:19 +0100 Subject: [PATCH 30/46] doc doc --- .../java/org/cryptomator/integrations/mount/MountBuilder.java | 2 +- .../org/cryptomator/integrations/mount/MountCapability.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index d6afc9a..d01934e 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -52,7 +52,7 @@ default MountBuilder setLoopbackPort(@Range(from = 0, to = Short.MAX_VALUE) int /** * Sets the mount point. *

- * Unless the mount provide supports {@link MountCapability#MOUNT_TO_SYSTEM_CHOSEN_PATH}, setting a mount point is required. + * Unless the mount service provider supports {@link MountCapability#MOUNT_TO_SYSTEM_CHOSEN_PATH}, setting a mount point is required. * * @param mountPoint Where to mount the volume * @return this diff --git a/src/main/java/org/cryptomator/integrations/mount/MountCapability.java b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java index 2b4a4cb..73ba871 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountCapability.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountCapability.java @@ -59,7 +59,7 @@ public enum MountCapability { MOUNT_AS_DRIVE_LETTER, /** - * The provider supports suggesting a default mount point, if no mount point is set via {@link MountBuilder#setMountpoint(Path)}. + * The service provider supports suggesting a default mount point, if no mount point is set via {@link MountBuilder#setMountpoint(Path)}. */ MOUNT_TO_SYSTEM_CHOSEN_PATH, From 2b86f334c087394bfa604fa07d2c098676cb5a53 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 8 Nov 2022 17:31:14 +0100 Subject: [PATCH 31/46] Add additional MountPoint.WithPath test for windows --- pom.xml | 5 +++++ .../integrations/mount/MountpointTest.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/pom.xml b/pom.xml index 34d6dbd..3e18fb0 100644 --- a/pom.xml +++ b/pom.xml @@ -92,6 +92,11 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M7 + maven-javadoc-plugin 3.2.0 diff --git a/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java b/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java index 7a123a3..377378b 100644 --- a/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java +++ b/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java @@ -3,6 +3,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import java.net.URI; import java.nio.file.Path; @@ -11,6 +14,7 @@ public class MountpointTest { @Test @DisplayName("MountPoint.forPath()") + @DisabledOnOs(OS.WINDOWS) public void testForPath() { var path = Path.of("/foo/bar"); var mountPoint = Mountpoint.forPath(path); @@ -23,6 +27,21 @@ public void testForPath() { } } + @Test + @DisplayName("MountPoint.forPath() (Windows)") + @EnabledOnOs(OS.WINDOWS) + public void testForPathWindows() { + var path = Path.of("D:\\foo\\bar"); + var mountPoint = Mountpoint.forPath(path); + + if (mountPoint instanceof Mountpoint.WithPath m) { + Assertions.assertEquals(path, m.path()); + Assertions.assertEquals(URI.create("file:///D:/foo/bar"), mountPoint.uri()); + } else { + Assertions.fail(); + } + } + @Test @DisplayName("MountPoint.forUri()") public void testForUri() { From cc96b77909b340d96d6fbe4a150cdf9966f33364 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 8 Nov 2022 17:31:57 +0100 Subject: [PATCH 32/46] fix tests by using try-with-scopes with closable objects --- .../common/ClassLoaderFactoryTest.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/test/java/org/cryptomator/integrations/common/ClassLoaderFactoryTest.java b/src/test/java/org/cryptomator/integrations/common/ClassLoaderFactoryTest.java index a5a8db5..2463966 100644 --- a/src/test/java/org/cryptomator/integrations/common/ClassLoaderFactoryTest.java +++ b/src/test/java/org/cryptomator/integrations/common/ClassLoaderFactoryTest.java @@ -47,12 +47,15 @@ public void setup(@TempDir Path tmpDir) throws IOException { @Test @DisplayName("can load resources from both jars") public void testForPluginDirWithPath() throws IOException { - var cl = ClassLoaderFactory.forPluginDirWithPath(pluginDir); - var fooContents = cl.getResourceAsStream("foo.properties").readAllBytes(); - var barContents = cl.getResourceAsStream("bar.properties").readAllBytes(); - - Assertions.assertArrayEquals(FOO_CONTENTS, fooContents); - Assertions.assertArrayEquals(BAR_CONTENTS, barContents); + try (var cl = ClassLoaderFactory.forPluginDirWithPath(pluginDir); + var fooIn = cl.getResourceAsStream("foo.properties"); + var barIn = cl.getResourceAsStream("bar.properties")) { + var fooContents = fooIn.readAllBytes(); + var barContents = barIn.readAllBytes(); + + Assertions.assertArrayEquals(FOO_CONTENTS, fooContents); + Assertions.assertArrayEquals(BAR_CONTENTS, barContents); + } } @Test @@ -60,12 +63,15 @@ public void testForPluginDirWithPath() throws IOException { public void testForPluginDirFromSysProp() throws IOException { System.setProperty("cryptomator.pluginDir", pluginDir.toString()); - var cl = ClassLoaderFactory.forPluginDir(); - var fooContents = cl.getResourceAsStream("foo.properties").readAllBytes(); - var barContents = cl.getResourceAsStream("bar.properties").readAllBytes(); + try (var cl = ClassLoaderFactory.forPluginDir(); + var fooIn = cl.getResourceAsStream("foo.properties"); + var barIn = cl.getResourceAsStream("bar.properties")) { + var fooContents = fooIn.readAllBytes(); + var barContents = barIn.readAllBytes(); - Assertions.assertArrayEquals(FOO_CONTENTS, fooContents); - Assertions.assertArrayEquals(BAR_CONTENTS, barContents); + Assertions.assertArrayEquals(FOO_CONTENTS, fooContents); + Assertions.assertArrayEquals(BAR_CONTENTS, barContents); + } } } @@ -126,7 +132,7 @@ public void testFindJars2(@TempDir Path tmpDir) throws IOException { var urls = ClassLoaderFactory.findJars(tmpDir); Arrays.sort(urls, Comparator.comparing(URL::toString)); - Assertions.assertArrayEquals(new URL[]{ + Assertions.assertArrayEquals(new URL[] { new URL(tmpDir.toUri() + "a.jar"), new URL(tmpDir.toUri() + "dir2/b.jar") }, urls); From 6c40aa9c8425194e1150b1c54ed273ea3f87b05b Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 8 Nov 2022 17:42:14 +0100 Subject: [PATCH 33/46] use three slashes in uri --- .../java/org/cryptomator/integrations/mount/MountpointTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java b/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java index 377378b..38bf6c2 100644 --- a/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java +++ b/src/test/java/org/cryptomator/integrations/mount/MountpointTest.java @@ -21,7 +21,7 @@ public void testForPath() { if (mountPoint instanceof Mountpoint.WithPath m) { Assertions.assertEquals(path, m.path()); - Assertions.assertEquals(URI.create("file:/foo/bar"), mountPoint.uri()); + Assertions.assertEquals(URI.create("file:///foo/bar"), mountPoint.uri()); } else { Assertions.fail(); } From 1de45cef0f435d9ca3c7d899c0fef535899cd655 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 10 Nov 2022 10:09:20 +0100 Subject: [PATCH 34/46] copy-paste error [ci skip] --- .../java/org/cryptomator/integrations/mount/MountBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java index d01934e..7c9f903 100644 --- a/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java +++ b/src/main/java/org/cryptomator/integrations/mount/MountBuilder.java @@ -109,7 +109,7 @@ default MountBuilder setVolumeId(String volumeId) { * * @param volumeName String conforming with the os-dependent naming restrictions * @return this - * @throws UnsupportedOperationException If {@link MountCapability#VOLUME_ID} is not supported + * @throws UnsupportedOperationException If {@link MountCapability#VOLUME_NAME} is not supported */ @Contract("_ -> this") default MountBuilder setVolumeName(String volumeName) { From e783125af9f8fb40e047c97627054b0c954b0b33 Mon Sep 17 00:00:00 2001 From: Vsevolod Golovanov Date: Tue, 13 Dec 2022 19:40:49 +0400 Subject: [PATCH 35/46] Tray-API: Add method to update tray icon #13 Added. --- .../cryptomator/integrations/tray/TrayMenuController.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java index 63edf14..80e69fd 100644 --- a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java @@ -30,6 +30,13 @@ static Optional get() { */ void showTrayIcon(byte[] imageData, Runnable defaultAction, String tooltip) throws TrayMenuException; + /** + * Updates an icon on the system tray. + * + * @param imageData What image to show + */ + void updateTrayIcon(byte[] imageData); + /** * Show the given options in the tray menu. *

From c7ecab8105edad15f4fde22b343282a6c31d2e12 Mon Sep 17 00:00:00 2001 From: Vsevolod Golovanov Date: Wed, 14 Dec 2022 00:58:06 +0400 Subject: [PATCH 36/46] Tray-API: Add method to update tray icon #13 Updated javadoc as requested. --- .../org/cryptomator/integrations/tray/TrayMenuController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java index 80e69fd..85f8c63 100644 --- a/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java +++ b/src/main/java/org/cryptomator/integrations/tray/TrayMenuController.java @@ -31,9 +31,10 @@ static Optional get() { void showTrayIcon(byte[] imageData, Runnable defaultAction, String tooltip) throws TrayMenuException; /** - * Updates an icon on the system tray. + * Updates the icon on the system tray. * * @param imageData What image to show + * @throws IllegalStateException thrown when called before an icon has been added */ void updateTrayIcon(byte[] imageData); From ce77d633a48a43f34547c1fad5059d490648ac89 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 6 Jan 2023 09:41:13 +0100 Subject: [PATCH 37/46] add common service interface --- .../common/IntegrationService.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/org/cryptomator/integrations/common/IntegrationService.java diff --git a/src/main/java/org/cryptomator/integrations/common/IntegrationService.java b/src/main/java/org/cryptomator/integrations/common/IntegrationService.java new file mode 100644 index 0000000..96d077a --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/common/IntegrationService.java @@ -0,0 +1,20 @@ +package org.cryptomator.integrations.common; + +public interface IntegrationService { + + + /** + * Name of this service implementation. + * + * @return A human readable name of this service implementation + */ + String displayName(); + + /** + * Indicates, if this service implemenation can be used. + * + * @return true, if this service implementation is supported in the current OS environment + * @implSpec This check needs to return fast and in constant time + */ + boolean isSupported(); +} From 178b7cc762e42e667ef2d5bc9d5ba6a6e30d8f08 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Sun, 8 Jan 2023 19:00:29 +0100 Subject: [PATCH 38/46] First api suggestion for reveal path service --- src/main/java/module-info.java | 3 ++ .../revealfiles/RevealFailedException.java | 17 ++++++++ .../revealfiles/RevealPathsService.java | 41 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/main/java/org/cryptomator/integrations/revealfiles/RevealFailedException.java create mode 100644 src/main/java/org/cryptomator/integrations/revealfiles/RevealPathsService.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 492b484..3f1ab9f 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,4 +1,5 @@ import org.cryptomator.integrations.mount.MountService; +import org.cryptomator.integrations.revealfiles.RevealPathsService; import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.keychain.KeychainAccessProvider; @@ -14,12 +15,14 @@ exports org.cryptomator.integrations.common; exports org.cryptomator.integrations.keychain; exports org.cryptomator.integrations.mount; + exports org.cryptomator.integrations.revealfiles; exports org.cryptomator.integrations.tray; exports org.cryptomator.integrations.uiappearance; uses AutoStartProvider; uses KeychainAccessProvider; uses MountService; + uses RevealPathsService; uses TrayIntegrationProvider; uses TrayMenuController; uses UiAppearanceProvider; diff --git a/src/main/java/org/cryptomator/integrations/revealfiles/RevealFailedException.java b/src/main/java/org/cryptomator/integrations/revealfiles/RevealFailedException.java new file mode 100644 index 0000000..a3e721d --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/revealfiles/RevealFailedException.java @@ -0,0 +1,17 @@ +package org.cryptomator.integrations.revealfiles; + +public class RevealFailedException extends Exception { + + public RevealFailedException(String msg) { + super(msg); + } + + public RevealFailedException(Exception cause) { + super(cause); + } + + public RevealFailedException(String msg, Exception cause) { + super(msg, cause); + } + +} diff --git a/src/main/java/org/cryptomator/integrations/revealfiles/RevealPathsService.java b/src/main/java/org/cryptomator/integrations/revealfiles/RevealPathsService.java new file mode 100644 index 0000000..24f8525 --- /dev/null +++ b/src/main/java/org/cryptomator/integrations/revealfiles/RevealPathsService.java @@ -0,0 +1,41 @@ +package org.cryptomator.integrations.revealfiles; + +import org.cryptomator.integrations.common.IntegrationService; +import org.cryptomator.integrations.common.IntegrationsLoader; + +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; + +public interface RevealPathsService extends IntegrationService { + + /** + * Loads all supported service implementations. + * + * @return Stream of supported RevealPathsService implementations (may be empty) + */ + static Stream get() { + return IntegrationsLoader.loadAll(RevealPathsService.class).filter(RevealPathsService::isSupported); + } + + /** + * Opens the parent of the given path in the system default file manager and highlights the resource the path points to. + * + * @throws RevealFailedException If the file manager could not be opened or {@code p} does not have a parent //TODO: or throw IllegalArgumenException + * @throws java.nio.file.NoSuchFileException If {@code p} does not exist + */ + void reveal(Path p) throws RevealFailedException, NoSuchFileException; + + /** + * Opens the given directory in the system default file manager and highlights all files from the list. + * + * @throws RevealFailedException If the file manager could not be opened + * @throws java.nio.file.NoSuchFileException If {@code directory} does not exist or is not a directory + * @throws RuntimeException If at least one file from the list cannot be found? TODO: this might be unncessary/not possible + * @throws UnsupportedOperationException If this service implementation does not support revealing multiple files + */ + default void reveal(Path directory, List childNames) throws RevealFailedException, NoSuchFileException { + throw new UnsupportedOperationException(); + } +} From e427caf8a3e7050c31279932bb8478adb0af8fcc Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 10 Jan 2023 13:51:08 +0100 Subject: [PATCH 39/46] Rename packages --- src/main/java/module-info.java | 4 ++-- .../{revealfiles => revealpaths}/RevealFailedException.java | 2 +- .../{revealfiles => revealpaths}/RevealPathsService.java | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) rename src/main/java/org/cryptomator/integrations/{revealfiles => revealpaths}/RevealFailedException.java (84%) rename src/main/java/org/cryptomator/integrations/{revealfiles => revealpaths}/RevealPathsService.java (89%) diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 3f1ab9f..b7c5e03 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,5 +1,5 @@ import org.cryptomator.integrations.mount.MountService; -import org.cryptomator.integrations.revealfiles.RevealPathsService; +import org.cryptomator.integrations.revealpaths.RevealPathsService; import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.keychain.KeychainAccessProvider; @@ -15,7 +15,7 @@ exports org.cryptomator.integrations.common; exports org.cryptomator.integrations.keychain; exports org.cryptomator.integrations.mount; - exports org.cryptomator.integrations.revealfiles; + exports org.cryptomator.integrations.revealpaths; exports org.cryptomator.integrations.tray; exports org.cryptomator.integrations.uiappearance; diff --git a/src/main/java/org/cryptomator/integrations/revealfiles/RevealFailedException.java b/src/main/java/org/cryptomator/integrations/revealpaths/RevealFailedException.java similarity index 84% rename from src/main/java/org/cryptomator/integrations/revealfiles/RevealFailedException.java rename to src/main/java/org/cryptomator/integrations/revealpaths/RevealFailedException.java index a3e721d..1f7ea37 100644 --- a/src/main/java/org/cryptomator/integrations/revealfiles/RevealFailedException.java +++ b/src/main/java/org/cryptomator/integrations/revealpaths/RevealFailedException.java @@ -1,4 +1,4 @@ -package org.cryptomator.integrations.revealfiles; +package org.cryptomator.integrations.revealpaths; public class RevealFailedException extends Exception { diff --git a/src/main/java/org/cryptomator/integrations/revealfiles/RevealPathsService.java b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java similarity index 89% rename from src/main/java/org/cryptomator/integrations/revealfiles/RevealPathsService.java rename to src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java index 24f8525..3db0f8d 100644 --- a/src/main/java/org/cryptomator/integrations/revealfiles/RevealPathsService.java +++ b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java @@ -1,4 +1,4 @@ -package org.cryptomator.integrations.revealfiles; +package org.cryptomator.integrations.revealpaths; import org.cryptomator.integrations.common.IntegrationService; import org.cryptomator.integrations.common.IntegrationsLoader; @@ -29,13 +29,15 @@ static Stream get() { /** * Opens the given directory in the system default file manager and highlights all files from the list. + * @param directory + * @param childNames * * @throws RevealFailedException If the file manager could not be opened * @throws java.nio.file.NoSuchFileException If {@code directory} does not exist or is not a directory * @throws RuntimeException If at least one file from the list cannot be found? TODO: this might be unncessary/not possible * @throws UnsupportedOperationException If this service implementation does not support revealing multiple files */ - default void reveal(Path directory, List childNames) throws RevealFailedException, NoSuchFileException { + default void reveal(Path directory, List childNames) throws RevealFailedException, NoSuchFileException { throw new UnsupportedOperationException(); } } From 78055f9c091c41c5d62e8684c57add1d051f9813 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 10 Jan 2023 14:28:05 +0100 Subject: [PATCH 40/46] Improved doc for revealPaths service --- .../integrations/revealpaths/RevealPathsService.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java index 3db0f8d..c2951b4 100644 --- a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java +++ b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java @@ -22,22 +22,25 @@ static Stream get() { /** * Opens the parent of the given path in the system default file manager and highlights the resource the path points to. * - * @throws RevealFailedException If the file manager could not be opened or {@code p} does not have a parent //TODO: or throw IllegalArgumenException + * @param p Path to reveal + * @throws RevealFailedException If the file manager could not be opened or {@code p} does not have a parent * @throws java.nio.file.NoSuchFileException If {@code p} does not exist */ + //TODO: Throw IllegalArgumenException if p.getParent() == null? void reveal(Path p) throws RevealFailedException, NoSuchFileException; /** * Opens the given directory in the system default file manager and highlights all files from the list. + * * @param directory * @param childNames - * * @throws RevealFailedException If the file manager could not be opened * @throws java.nio.file.NoSuchFileException If {@code directory} does not exist or is not a directory - * @throws RuntimeException If at least one file from the list cannot be found? TODO: this might be unncessary/not possible + * @throws IllegalArgumentException If {@code childNames} contains non-relative paths or paths with a name count != 1 in normalized form * @throws UnsupportedOperationException If this service implementation does not support revealing multiple files */ default void reveal(Path directory, List childNames) throws RevealFailedException, NoSuchFileException { throw new UnsupportedOperationException(); } + } From 53f7b5726c79e238e6c3a7dd5b0ba0235882a7f6 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 10 Jan 2023 14:28:32 +0100 Subject: [PATCH 41/46] simplify api (for now) --- .../revealpaths/RevealPathsService.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java index c2951b4..ce24bae 100644 --- a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java +++ b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java @@ -29,18 +29,4 @@ static Stream get() { //TODO: Throw IllegalArgumenException if p.getParent() == null? void reveal(Path p) throws RevealFailedException, NoSuchFileException; - /** - * Opens the given directory in the system default file manager and highlights all files from the list. - * - * @param directory - * @param childNames - * @throws RevealFailedException If the file manager could not be opened - * @throws java.nio.file.NoSuchFileException If {@code directory} does not exist or is not a directory - * @throws IllegalArgumentException If {@code childNames} contains non-relative paths or paths with a name count != 1 in normalized form - * @throws UnsupportedOperationException If this service implementation does not support revealing multiple files - */ - default void reveal(Path directory, List childNames) throws RevealFailedException, NoSuchFileException { - throw new UnsupportedOperationException(); - } - } From d3f9a24456ff71bfdf6c4af3e32ad7f076bf043f Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 10 Jan 2023 16:08:23 +0100 Subject: [PATCH 42/46] Revert "add common service interface" This reverts commit ce77d633a48a43f34547c1fad5059d490648ac89. --- .../common/IntegrationService.java | 20 ------------------- .../revealpaths/RevealPathsService.java | 12 ++++++++--- 2 files changed, 9 insertions(+), 23 deletions(-) delete mode 100644 src/main/java/org/cryptomator/integrations/common/IntegrationService.java diff --git a/src/main/java/org/cryptomator/integrations/common/IntegrationService.java b/src/main/java/org/cryptomator/integrations/common/IntegrationService.java deleted file mode 100644 index 96d077a..0000000 --- a/src/main/java/org/cryptomator/integrations/common/IntegrationService.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.cryptomator.integrations.common; - -public interface IntegrationService { - - - /** - * Name of this service implementation. - * - * @return A human readable name of this service implementation - */ - String displayName(); - - /** - * Indicates, if this service implemenation can be used. - * - * @return true, if this service implementation is supported in the current OS environment - * @implSpec This check needs to return fast and in constant time - */ - boolean isSupported(); -} diff --git a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java index ce24bae..12252ed 100644 --- a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java +++ b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java @@ -1,14 +1,12 @@ package org.cryptomator.integrations.revealpaths; -import org.cryptomator.integrations.common.IntegrationService; import org.cryptomator.integrations.common.IntegrationsLoader; import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.util.List; import java.util.stream.Stream; -public interface RevealPathsService extends IntegrationService { +public interface RevealPathsService { /** * Loads all supported service implementations. @@ -29,4 +27,12 @@ static Stream get() { //TODO: Throw IllegalArgumenException if p.getParent() == null? void reveal(Path p) throws RevealFailedException, NoSuchFileException; + /** + * Indicates, if this provider can be used. + * + * @return true, if this provider is supported in the current OS environment + * @implSpec This check needs to return fast and in constant time + */ + boolean isSupported(); + } From 38531599b8e99c16638b4670f99def8e2ba61d0b Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 10 Jan 2023 16:22:44 +0100 Subject: [PATCH 43/46] Change specification --- .../integrations/revealpaths/RevealPathsService.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java index 12252ed..0da91cb 100644 --- a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java +++ b/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java @@ -9,7 +9,7 @@ public interface RevealPathsService { /** - * Loads all supported service implementations. + * Loads all supported service providers. * * @return Stream of supported RevealPathsService implementations (may be empty) */ @@ -21,10 +21,9 @@ static Stream get() { * Opens the parent of the given path in the system default file manager and highlights the resource the path points to. * * @param p Path to reveal - * @throws RevealFailedException If the file manager could not be opened or {@code p} does not have a parent - * @throws java.nio.file.NoSuchFileException If {@code p} does not exist + * @throws RevealFailedException If the file manager could not be opened + * @throws IllegalArgumentException If {@code p} does not have a parent */ - //TODO: Throw IllegalArgumenException if p.getParent() == null? void reveal(Path p) throws RevealFailedException, NoSuchFileException; /** From 9d8080080d09324b0a2e29fadff6eda4b91295ad Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 11 Jan 2023 10:00:32 +0100 Subject: [PATCH 44/46] Rename service (and package) to singular form --- src/main/java/module-info.java | 6 +++--- .../RevealFailedException.java | 2 +- .../RevealPathService.java} | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) rename src/main/java/org/cryptomator/integrations/{revealpaths => revealpath}/RevealFailedException.java (84%) rename src/main/java/org/cryptomator/integrations/{revealpaths/RevealPathsService.java => revealpath/RevealPathService.java} (80%) diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index b7c5e03..7108775 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,5 +1,5 @@ import org.cryptomator.integrations.mount.MountService; -import org.cryptomator.integrations.revealpaths.RevealPathsService; +import org.cryptomator.integrations.revealpath.RevealPathService; import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.keychain.KeychainAccessProvider; @@ -15,14 +15,14 @@ exports org.cryptomator.integrations.common; exports org.cryptomator.integrations.keychain; exports org.cryptomator.integrations.mount; - exports org.cryptomator.integrations.revealpaths; + exports org.cryptomator.integrations.revealpath; exports org.cryptomator.integrations.tray; exports org.cryptomator.integrations.uiappearance; uses AutoStartProvider; uses KeychainAccessProvider; uses MountService; - uses RevealPathsService; + uses RevealPathService; uses TrayIntegrationProvider; uses TrayMenuController; uses UiAppearanceProvider; diff --git a/src/main/java/org/cryptomator/integrations/revealpaths/RevealFailedException.java b/src/main/java/org/cryptomator/integrations/revealpath/RevealFailedException.java similarity index 84% rename from src/main/java/org/cryptomator/integrations/revealpaths/RevealFailedException.java rename to src/main/java/org/cryptomator/integrations/revealpath/RevealFailedException.java index 1f7ea37..c56b6f9 100644 --- a/src/main/java/org/cryptomator/integrations/revealpaths/RevealFailedException.java +++ b/src/main/java/org/cryptomator/integrations/revealpath/RevealFailedException.java @@ -1,4 +1,4 @@ -package org.cryptomator.integrations.revealpaths; +package org.cryptomator.integrations.revealpath; public class RevealFailedException extends Exception { diff --git a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java b/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java similarity index 80% rename from src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java rename to src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java index 0da91cb..818ae18 100644 --- a/src/main/java/org/cryptomator/integrations/revealpaths/RevealPathsService.java +++ b/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java @@ -1,4 +1,4 @@ -package org.cryptomator.integrations.revealpaths; +package org.cryptomator.integrations.revealpath; import org.cryptomator.integrations.common.IntegrationsLoader; @@ -6,15 +6,15 @@ import java.nio.file.Path; import java.util.stream.Stream; -public interface RevealPathsService { +public interface RevealPathService { /** * Loads all supported service providers. * * @return Stream of supported RevealPathsService implementations (may be empty) */ - static Stream get() { - return IntegrationsLoader.loadAll(RevealPathsService.class).filter(RevealPathsService::isSupported); + static Stream get() { + return IntegrationsLoader.loadAll(RevealPathService.class).filter(RevealPathService::isSupported); } /** From a7b1eb65f32f7e8391455cbd86cc82ff2ac476fd Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 11 Jan 2023 10:34:28 +0100 Subject: [PATCH 45/46] change spec: * for files, select file in file manager * for directory, just open dir in file manager --- .../integrations/revealpath/RevealPathService.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java b/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java index 818ae18..4ca0970 100644 --- a/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java +++ b/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java @@ -2,7 +2,6 @@ import org.cryptomator.integrations.common.IntegrationsLoader; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.stream.Stream; @@ -18,13 +17,15 @@ static Stream get() { } /** - * Opens the parent of the given path in the system default file manager and highlights the resource the path points to. + * Reveal the path in the system default file manager. + *

+ * If the path points to a file, the parent of the file is openend and file is selected in the file manager window. + * If the path points to a directory, the directory is opened and its content shown in the file manager window. * * @param p Path to reveal - * @throws RevealFailedException If the file manager could not be opened - * @throws IllegalArgumentException If {@code p} does not have a parent + * @throws RevealFailedException if revealing the path failed */ - void reveal(Path p) throws RevealFailedException, NoSuchFileException; + void reveal(Path p) throws RevealFailedException; /** * Indicates, if this provider can be used. From c08b8a7e588a2fea8dccf1423cb4978eb6b979d3 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 11 Jan 2023 10:38:55 +0100 Subject: [PATCH 46/46] Apply suggestions from code review Co-authored-by: Tobias Hagemann --- .../integrations/revealpath/RevealPathService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java b/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java index 4ca0970..db7442e 100644 --- a/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java +++ b/src/main/java/org/cryptomator/integrations/revealpath/RevealPathService.java @@ -10,7 +10,7 @@ public interface RevealPathService { /** * Loads all supported service providers. * - * @return Stream of supported RevealPathsService implementations (may be empty) + * @return Stream of supported RevealPathService implementations (may be empty) */ static Stream get() { return IntegrationsLoader.loadAll(RevealPathService.class).filter(RevealPathService::isSupported); @@ -19,7 +19,7 @@ static Stream get() { /** * Reveal the path in the system default file manager. *

- * If the path points to a file, the parent of the file is openend and file is selected in the file manager window. + * If the path points to a file, the parent of the file is opened and the file is selected in the file manager window. * If the path points to a directory, the directory is opened and its content shown in the file manager window. * * @param p Path to reveal