more Sparkle tests

This commit is contained in:
Micha
2025-11-26 20:09:06 +01:00
parent 9a6609df7b
commit 5905ae5aa7
2 changed files with 75 additions and 0 deletions

View File

@@ -81,6 +81,16 @@ Preferences expose Sparkles built-in toggles for “Automatically check” an
> Build settings include `INFOPLIST_KEY_SUFeedURL` and `INFOPLIST_KEY_SUPublicEDKey`. Make sure to fill both before shipping a build so Sparkle knows where to fetch updates and how to verify them.
#### Debugging Sparkle updates
Launch the shipped app via CLI with `SPARKLE_VERBOSE_LOGGING=1` to mirror Sparkles activity in stdout/stderr:
```bash
SPARKLE_VERBOSE_LOGGING=1 /Applications/iKeyMon.app/Contents/MacOS/iKeyMon
```
Sparkles installer helper runs in a separate `SUPipedBinary` process. If the installer fails, collect additional details with `log show --process SUPipedBinary --last 5m`.
### Automated release push
If you want `git push origin master` to build/sign/notarize/upload automatically, enable the provided pre-push hook:

View File

@@ -1,13 +1,19 @@
import Sparkle
import Foundation
import OSLog
@MainActor
final class SparkleUpdater: NSObject, ObservableObject {
let controller: SPUStandardUpdaterController
private let logger = Logger(subsystem: "net.24unix.iKeyMon", category: "Sparkle")
private let verboseLogging: Bool
override init() {
self.verboseLogging = ProcessInfo.processInfo.environment["SPARKLE_VERBOSE_LOGGING"] == "1"
self.controller = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil)
super.init()
controller.updater.delegate = self
log("Sparkle updater initialized (verbose=\(verboseLogging)).")
}
var automaticallyChecksForUpdates: Bool {
@@ -21,6 +27,65 @@ final class SparkleUpdater: NSObject, ObservableObject {
}
func checkForUpdates() {
log("Manual check for updates triggered.")
controller.checkForUpdates(nil)
}
private func log(_ message: String) {
logger.log("\(message, privacy: .public)")
if verboseLogging {
print("[Sparkle] \(message)")
}
}
private func logError(_ message: String) {
logger.error("\(message, privacy: .public)")
if verboseLogging {
fputs("[Sparkle][error] \(message)\n", stderr)
}
}
private func describe(update item: SUAppcastItem) -> String {
let short = item.displayVersionString ?? item.versionString ?? "unknown"
let build = item.versionString ?? "?"
return "\(short) (build \(build))"
}
}
extension SparkleUpdater: SPUUpdaterDelegate {
func updater(_ updater: SPUUpdater, didFinishLoading appcast: SUAppcast) {
log("Loaded Sparkle appcast containing \(appcast.items.count) item(s).")
}
func updater(_ updater: SPUUpdater, didFindValidUpdate item: SUAppcastItem) {
log("Found valid update \(describe(update: item))")
}
func updaterDidNotFindUpdate(_ updater: SPUUpdater) {
log("No updates available.")
}
func updater(_ updater: SPUUpdater, willDownloadUpdate item: SUAppcastItem, with request: NSMutableURLRequest) {
log("Downloading \(describe(update: item)) from \(request.url?.absoluteString ?? "unknown URL")")
}
func updater(_ updater: SPUUpdater, didDownloadUpdate item: SUAppcastItem) {
log("Finished downloading \(describe(update: item))")
}
func updater(_ updater: SPUUpdater, failedToDownloadUpdate item: SUAppcastItem, error: Error) {
logError("Failed to download \(describe(update: item)): \(error.localizedDescription)")
}
func userDidCancelDownload(_ updater: SPUUpdater) {
log("User cancelled Sparkle download.")
}
func updater(_ updater: SPUUpdater, willInstallUpdate item: SUAppcastItem) {
log("Will install update \(describe(update: item))")
}
func updater(_ updater: SPUUpdater, didAbortWithError error: Error) {
logError("Sparkle aborted: \(error.localizedDescription)")
}
}