-
Notifications
You must be signed in to change notification settings - Fork 5
External update mechanism #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
WalkthroughThis change introduces a new update mechanism API within the Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 15
🧹 Nitpick comments (11)
src/main/java/org/cryptomator/integrations/update/UpdateFailedException.java (1)
3-12
: Add JavaDoc documentation for better API usability.The exception class follows standard Java patterns correctly. Consider adding JavaDoc to document when this exception is thrown and its purpose in the update framework.
+/** + * Thrown when an update operation fails or is cancelled. + * This exception may wrap underlying causes of update failures. + */ public class UpdateFailedException extends Exception { + /** + * Constructs an UpdateFailedException with the specified detail message. + * + * @param message the detail message + */ public UpdateFailedException(String message) { super(message); } + /** + * Constructs an UpdateFailedException with the specified detail message and cause. + * + * @param message the detail message + * @param cause the cause of the exception + */ public UpdateFailedException(String message, Throwable cause) { super(message, cause); } }src/main/java/org/cryptomator/integrations/update/ProgressListener.java (1)
3-6
: Add JavaDoc documentation for the functional interface.The functional interface design is clean and follows best practices. Consider adding JavaDoc to document the contract and usage.
+/** + * Functional interface for listening to progress updates during update operations. + */ @FunctionalInterface public interface ProgressListener { + /** + * Called when progress is made during an update operation. + * + * @param progress the current progress information + */ void onProgress(Progress progress); }src/main/java/org/cryptomator/integrations/update/UpdateAvailableListener.java (1)
3-6
: Add JavaDoc documentation for consistency with other API interfaces.The functional interface follows the same clean pattern as other listeners in the package. Consider adding JavaDoc documentation for consistency.
+/** + * Functional interface for listening to update availability notifications. + */ @FunctionalInterface public interface UpdateAvailableListener { + /** + * Called when an update becomes available. + * + * @param updateAvailable information about the available update + */ void onUpdateAvailable(UpdateAvailable updateAvailable); }src/main/java/org/cryptomator/integrations/update/SpawnExitedListener.java (1)
3-6
: Complete the documentation set for all listener interfaces.The functional interface maintains consistency with other listeners in the package. Adding JavaDoc will complete the documentation set for the update API.
+/** + * Functional interface for listening to spawned process exit events during updates. + */ @FunctionalInterface public interface SpawnExitedListener { + /** + * Called when a spawned process exits during the update process. + * + * @param spawnExited information about the exited process + */ void onSpawnExited(SpawnExited spawnExited); }src/main/java/org/cryptomator/integrations/update/UpdateService.java (3)
9-11
: Fix typos in class documentation.There are several spelling errors in the class-level JavaDoc.
- * This is the interface used by Cryptomator to provide a way to update Cryptomator in a convinient way. - * It's idependent of the supported platforms and package distribution channels. + * This is the interface used by Cryptomator to provide a way to update Cryptomator in a convenient way. + * It's independent of the supported platforms and package distribution channels.
19-22
: Fix typos in method documentation.Multiple spelling errors in the
isSupported()
method documentation.- * @return <code>true</code> if this UppdateService can update the app. + * @return <code>true</code> if this UpdateService can update the app. * @implSpec This method must not throw any exceptions and should fail fast - * returning <code>false</code> if it's not possible to use this UppdateService + * returning <code>false</code> if it's not possible to use this UpdateService
36-36
: Fix typo in exception documentation.Spelling error in the
@throws
documentation.- * @throws UpdateFailedException If the udpate wasn't successful or was cancelled. + * @throws UpdateFailedException If the update wasn't successful or was cancelled.src/main/java/org/cryptomator/integrations/update/SpawnStartedListener.java (1)
4-5
: Consider adding null safety documentation.The functional interface design is clean and follows Java conventions. However, consider adding documentation to clarify whether the
spawnStarted
parameter can be null to prevent potential NPEs in implementations.@FunctionalInterface public interface SpawnStartedListener { + /** + * Called when a spawn process has started. + * @param spawnStarted the spawn information, must not be null + */ void onSpawnStarted(SpawnStarted spawnStarted); }src/main/java/org/cryptomator/integrations/update/SpawnStarted.java (1)
3-14
: Consider adding equals, hashCode, and toString methods.Data classes typically benefit from proper equals/hashCode implementation for use in collections and toString for debugging. Also, consider adding documentation to explain what
relPid
represents.+/** + * Represents information about a spawned process. + * @param pid the process ID + * @param relPid the relative process ID (explain what this means) + */ public class SpawnStarted { private final long pid; private final long relPid; // ... existing code ... public long getPid() { return pid; } public long getRelPid() { return relPid; } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + SpawnStarted that = (SpawnStarted) obj; + return pid == that.pid && relPid == that.relPid; + } + + @Override + public int hashCode() { + return Long.hashCode(pid) * 31 + Long.hashCode(relPid); + } + + @Override + public String toString() { + return "SpawnStarted{pid=" + pid + ", relPid=" + relPid + '}'; + } }src/main/java/org/cryptomator/integrations/update/SpawnExited.java (1)
3-14
: Consider adding equals, hashCode, and toString methods.For consistency with data class best practices and to enable proper usage in collections and debugging scenarios.
+/** + * Represents information about a spawned process that has exited. + */ public class SpawnExited { private final long pid; private final long exitStatus; // ... existing code ... public long getPid() { return pid; } public long getExitStatus() { return exitStatus; } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + SpawnExited that = (SpawnExited) obj; + return pid == that.pid && exitStatus == that.exitStatus; + } + + @Override + public int hashCode() { + return Long.hashCode(pid) * 31 + Long.hashCode(exitStatus); + } + + @Override + public String toString() { + return "SpawnExited{pid=" + pid + ", exitStatus=" + exitStatus + '}'; + } }src/main/java/org/cryptomator/integrations/update/UpdateAvailable.java (1)
3-23
: Consider adding equals, hashCode, toString, and documentation.For consistency with data class best practices and to provide clarity on what each commit type represents.
+/** + * Represents information about available software updates. + * Contains commit references for running, local, and remote versions. + */ public class UpdateAvailable { private final String runningCommit; private final String localCommit; private final String remoteCommit; // ... existing code ... + /** + * @return the commit hash of the currently running version + */ public String getRunningCommit() { return runningCommit; } + /** + * @return the commit hash of the locally available version + */ public String getLocalCommit() { return localCommit; } + /** + * @return the commit hash of the remote version + */ public String getRemoteCommit() { return remoteCommit; } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + UpdateAvailable that = (UpdateAvailable) obj; + return Objects.equals(runningCommit, that.runningCommit) && + Objects.equals(localCommit, that.localCommit) && + Objects.equals(remoteCommit, that.remoteCommit); + } + + @Override + public int hashCode() { + return Objects.hash(runningCommit, localCommit, remoteCommit); + } + + @Override + public String toString() { + return "UpdateAvailable{" + + "runningCommit='" + runningCommit + '\'' + + ", localCommit='" + localCommit + '\'' + + ", remoteCommit='" + remoteCommit + '\'' + + '}'; + } }You'll need to add this import:
+import java.util.Objects;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
src/main/java/module-info.java
(3 hunks)src/main/java/org/cryptomator/integrations/common/DistributionChannel.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/Progress.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/ProgressListener.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/SpawnExited.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/SpawnExitedListener.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/SpawnStarted.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/SpawnStartedListener.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/UpdateAvailable.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/UpdateAvailableListener.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/UpdateFailedException.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/UpdateService.java
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/org/cryptomator/integrations/update/UpdateService.java (1)
src/main/java/org/cryptomator/integrations/common/IntegrationsLoader.java (1)
IntegrationsLoader
(19-163)
🔇 Additional comments (7)
src/main/java/org/cryptomator/integrations/common/DistributionChannel.java (1)
12-41
: Well-designed annotation following Java best practices.The annotation implementation is excellent:
- Proper retention policy for runtime access
- Correct use of repeatable annotation pattern
- Comprehensive enum values covering major distribution channels
- Appropriate experimental marking for new API
- Safe default value (UNKNOWN)
src/main/java/module-info.java (6)
9-9
: LGTM!The import statement is correctly added for the new UpdateService.
24-24
: LGTM!The package export is correctly added to make the update integration API accessible.
34-34
: LGTM!The service usage declaration is correctly added to enable service loading of UpdateService implementations.
9-9
: LGTM!The import statement correctly references the new UpdateService interface, following the existing pattern in the module descriptor.
24-24
: LGTM!The export declaration properly exposes the new update package to other modules, maintaining consistency with the existing export structure.
34-34
: LGTM!The uses declaration correctly enables service loading for UpdateService, which is essential for the integration API pattern used throughout this module.
src/main/java/org/cryptomator/integrations/update/Progress.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/Progress.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/Progress.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/Progress.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/SpawnExited.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateAvailable.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateService.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateService.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateService.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateService.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Impressive overall proof of concept, however I believe the API can and needs to be more generic. After all we want the new API to be a common denominator for basically all update mechanisms.
I imagine a very lean API (as suggested in a separate PoC: UpdateMechanism and UpdateProcess)
src/main/java/org/cryptomator/integrations/common/DistributionChannel.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/Progress.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateService.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateService.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateService.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateService.java
Outdated
Show resolved
Hide resolved
Foremost, thanks for the quick review, and thanks for the suggestion on how to change the API to fit together with your PoC - UpdateMechanism and UpdateProcess. |
Changes to correlate with API as suggested in PoC: UpdateMechanism and UpdateProcess were implemented and tested. @overheadhunter Tested again with integrations-linux and Cryptomator. Hopefully, no more changes to integrations-api are needed. 🤞🏻 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Nitpick comments (2)
src/main/java/org/cryptomator/integrations/update/UpdateProcess.java (2)
31-40
: Clarifyawait(timeout)
return valueThe Javadoc states “returns true if the update is prepared” but omits what
false
means (timeout vs. error vs. cancellation). Document all possible outcomes to avoid misuse.
48-51
: Expose consistent failure semantics
applyUpdate()
throwsIOException
, whileprepareUpdate()
inUpdateMechanism
throws the customUpdateFailedException
. For symmetry (and simpler caller handling) consider using the same checked exception type here as well.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/main/java/module-info.java
(3 hunks)src/main/java/org/cryptomator/integrations/update/DownloadUpdateProcess.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/UpdateFailedException.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/UpdateMechanism.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/UpdateProcess.java
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/main/java/org/cryptomator/integrations/update/UpdateFailedException.java
- src/main/java/module-info.java
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/org/cryptomator/integrations/update/UpdateProcess.java (1)
src/main/java/org/cryptomator/integrations/update/UpdateFailedException.java (1)
ApiStatus
(7-17)
src/main/java/org/cryptomator/integrations/update/DownloadUpdateProcess.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/DownloadUpdateProcess.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/DownloadUpdateProcess.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/DownloadUpdateProcess.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/DownloadUpdateProcess.java
Outdated
Show resolved
Hide resolved
static UpdateMechanism get() { | ||
return IntegrationsLoader.load(UpdateMechanism.class).orElseThrow(); // Fallback "show download page" mechanism always available. | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
orElseThrow()
loses diagnostic context
If no implementation is found the caller gets a naked NoSuchElementException
without guidance. Provide a descriptive message or fall back to the “show-download-page” implementation directly.
🤖 Prompt for AI Agents
In src/main/java/org/cryptomator/integrations/update/UpdateMechanism.java around
lines 11 to 13, the use of orElseThrow() without a message causes a generic
NoSuchElementException with no diagnostic context if no implementation is found.
Fix this by either providing a descriptive exception message in orElseThrow() or
by returning a default fallback implementation that shows the download page
directly to improve error clarity and handling.
src/main/java/org/cryptomator/integrations/update/UpdateMechanism.java
Outdated
Show resolved
Hide resolved
src/main/java/org/cryptomator/integrations/update/UpdateProcess.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (1)
src/main/java/org/cryptomator/integrations/update/DownloadUpdateProcess.java (1)
163-170
: EOF handling inverted – negative length fed toMessageDigest
The condition should ben > 0
; passing ‑1 todigest.update
andcounter.add
throwsIllegalArgumentException
and corrupts progress.-if (n == -1) { - digest.update(b, off, n); - counter.add(n); -} +if (n > 0) { + digest.update(b, off, n); + counter.add(n); +}
🧹 Nitpick comments (3)
src/main/java/org/cryptomator/integrations/update/SemVerComparator.java (1)
9-13
: Make the comparator non-instantiable and clearly singletonSince an INSTANCE is provided, prevent additional instantiation and clarify intent.
Apply this diff:
-public class SemVerComparator implements Comparator<String> { +public final class SemVerComparator implements Comparator<String> { public static final SemVerComparator INSTANCE = new SemVerComparator(); + + private SemVerComparator() { + // singleton + }src/main/java/org/cryptomator/integrations/update/DownloadUpdateProcess.java (2)
48-53
:this
still captured during construction
Moving thestart()
call out is an improvement, but the thread capturingthis
is still created before the object is fully constructed. Consider building/starting the thread instartDownload()
instead to avoid premature escape entirely.
55-63
: Progress can exceed 1.0
If the final download size differs from the initial estimate,loadedBytes
may outruntotalBytes
, yielding values > 1. Clamp the result to1.0
for predictable progress reporting.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/main/java/org/cryptomator/integrations/update/DownloadUpdateProcess.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/SemVerComparator.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/UpdateMechanism.java
(1 hunks)src/main/java/org/cryptomator/integrations/update/UpdateProcess.java
(1 hunks)src/test/java/org/cryptomator/integrations/update/SemVerComparatorTest.java
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/main/java/org/cryptomator/integrations/update/UpdateMechanism.java
- src/main/java/org/cryptomator/integrations/update/UpdateProcess.java
🔇 Additional comments (1)
src/test/java/org/cryptomator/integrations/update/SemVerComparatorTest.java (1)
10-75
: Good coverage of SemVer precedence, including build metadata and spec’s exampleThe tests validate equality, ordering, and the spec’s precedence example. Solid baseline.
No description provided.