-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix Sparkle signing and installer fallback #1962
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: main
Are you sure you want to change the base?
Changes from 3 commits
85602c5
3814ad2
64474cc
0c65f39
f77e7d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,9 @@ import SwiftUI | |
| import Sparkle | ||
|
|
||
| class UpdateViewModel: ObservableObject { | ||
| static let manualDownloadDMGURLString = "https://github.com/manaflow-ai/cmux/releases/latest/download/cmux-macos.dmg" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new fallback link is hardcoded to the stable asset ( Useful? React with 👍 / 👎. |
||
| static let manualDownloadNightlyDMGURLString = "https://github.com/manaflow-ai/cmux/releases/download/nightly/cmux-nightly-macos.dmg" | ||
|
|
||
| @Published var state: UpdateState = .idle | ||
| @Published var overrideState: UpdateState? | ||
| @Published var detectedUpdateVersion: String? | ||
|
|
@@ -235,8 +238,8 @@ class UpdateViewModel: ObservableObject { | |
| } | ||
| if nsError.domain == SUSparkleErrorDomain { | ||
| switch nsError.code { | ||
| case 4005: | ||
| return String(localized: "update.error.permissionError.title", defaultValue: "Updater Permission Error") | ||
| case 4000, 4001, 4002, 4003, 4004, 4005, 4010, 4012: | ||
| return String(localized: "update.error.installationFailed.title", defaultValue: "Update Installation Failed") | ||
| case 2001: | ||
| return String(localized: "update.error.downloadFailed.title", defaultValue: "Couldn't Download Update") | ||
| case 1000, 1002: | ||
|
|
@@ -282,6 +285,8 @@ class UpdateViewModel: ObservableObject { | |
| } | ||
| if nsError.domain == SUSparkleErrorDomain { | ||
| switch nsError.code { | ||
| case 4000, 4001, 4002, 4003, 4004, 4005, 4010, 4012: | ||
| return String(localized: "update.error.installationFailed.message", defaultValue: "cmux couldn't install the downloaded update. Download the latest DMG to update manually.") | ||
| case 2001: | ||
| return String(localized: "update.error.feedDownload.message", defaultValue: "cmux couldn't download the update feed. Check your connection and try again.") | ||
| case 1000, 1002: | ||
|
|
@@ -292,7 +297,7 @@ class UpdateViewModel: ObservableObject { | |
| return String(localized: "update.error.insecureFeed.message", defaultValue: "The update feed is insecure. Please contact support.") | ||
| case 1, 2, 3001, 3002: | ||
| return String(localized: "update.error.signatureError.message", defaultValue: "The update's signature could not be verified. Please try again later.") | ||
| case 1003, 1005, 4005: | ||
| case 1003, 1005: | ||
| return String(localized: "update.error.permissionError.message", defaultValue: "Move cmux into Applications and relaunch to enable updates.") | ||
| default: | ||
| break | ||
|
|
@@ -340,6 +345,14 @@ class UpdateViewModel: ObservableObject { | |
| return lines.joined(separator: "\n") | ||
| } | ||
|
|
||
| static func manualDownloadURL(for error: Swift.Error) -> URL? { | ||
| let nsError = error as NSError | ||
| guard shouldOfferManualDownload(for: nsError) else { return nil } | ||
| let infoFeedURL = Bundle.main.object(forInfoDictionaryKey: "SUFeedURL") as? String | ||
| let isNightly = UpdateFeedResolver.resolvedFeedURLString(infoFeedURL: infoFeedURL).isNightly | ||
| return URL(string: isNightly ? manualDownloadNightlyDMGURLString : manualDownloadDMGURLString) | ||
| } | ||
|
|
||
| private static func networkError(from error: NSError) -> NSError? { | ||
| if error.domain == NSURLErrorDomain { | ||
| return error | ||
|
|
@@ -357,6 +370,14 @@ class UpdateViewModel: ObservableObject { | |
| case 2: return "SUInsufficientSigningError" | ||
| case 3: return "SUInsecureFeedURLError" | ||
| case 4: return "SUInvalidFeedURLError" | ||
| case 4000: return "SUFileCopyFailure" | ||
| case 4001: return "SUAuthenticationFailure" | ||
| case 4002: return "SUMissingUpdateError" | ||
| case 4003: return "SUMissingInstallerToolError" | ||
| case 4004: return "SURelaunchError" | ||
| case 4005: return "SUInstallationError" | ||
| case 4010: return "SUAgentInvalidationError" | ||
| case 4012: return "SUInstallationWriteNoPermissionError" | ||
| case 1000: return "SUAppcastParseError" | ||
| case 1001: return "SUNoUpdateError" | ||
| case 1002: return "SUAppcastError" | ||
|
|
@@ -370,6 +391,19 @@ class UpdateViewModel: ObservableObject { | |
| } | ||
| } | ||
|
|
||
| private static func shouldOfferManualDownload(for error: NSError) -> Bool { | ||
| guard error.domain == SUSparkleErrorDomain else { | ||
| return false | ||
| } | ||
|
|
||
| switch error.code { | ||
| case 4000, 4001, 4002, 4003, 4004, 4005, 4010, 4012: | ||
| return true | ||
| default: | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| static func normalizedDetectedUpdateVersion(from version: String) -> String? { | ||
| let trimmed = version.trimmingCharacters(in: .whitespacesAndNewlines) | ||
| return trimmed.isEmpty ? nil : trimmed | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.