Redline: timestamped result for the manual update check, update-state renders, and a duplicated-status fix (MMDB-2697) #27
@@ -2,6 +2,7 @@ import AppKit
|
|||||||
import CryptoKit
|
import CryptoKit
|
||||||
import Foundation
|
import Foundation
|
||||||
import Security
|
import Security
|
||||||
|
import ShotdeckCore
|
||||||
|
|
||||||
/// Built-in updater. Checks an appcast, stages a verified payload, and installs
|
/// Built-in updater. Checks an appcast, stages a verified payload, and installs
|
||||||
/// only when the user clicks the menu row — never automatically.
|
/// only when the user clicks the menu row — never automatically.
|
||||||
@@ -31,6 +32,10 @@ final class UpdateChecker {
|
|||||||
private var repeatingTimer: Timer?
|
private var repeatingTimer: Timer?
|
||||||
private var firstCheckTask: Task<Void, Never>?
|
private var firstCheckTask: Task<Void, Never>?
|
||||||
private var stagingDirectory: URL?
|
private var stagingDirectory: URL?
|
||||||
|
/// Snapshot-only override for previousVersion; when snapshotUsesPreviousVersionOverride is true,
|
||||||
|
/// this value (including nil) is returned instead of checking the file system.
|
||||||
|
var snapshotPreviousVersionOverride: String?
|
||||||
|
var snapshotUsesPreviousVersionOverride: Bool = false
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let config = URLSessionConfiguration.ephemeral
|
let config = URLSessionConfiguration.ephemeral
|
||||||
@@ -85,7 +90,12 @@ final class UpdateChecker {
|
|||||||
|
|
||||||
guard Self.isNewer(appcast.version, than: Self.currentVersion()) else {
|
guard Self.isNewer(appcast.version, than: Self.currentVersion()) else {
|
||||||
clearOffer()
|
clearOffer()
|
||||||
statusMessage = manual ? "Redline \(Self.currentVersion()) is up to date." : nil
|
if manual {
|
||||||
|
let timestamp = DubaiTime.checkTime(lastCheckedAt ?? Date())
|
||||||
|
statusMessage = "Redline \(Self.currentVersion()) is up to date, checked \(timestamp)"
|
||||||
|
} else {
|
||||||
|
statusMessage = nil
|
||||||
|
}
|
||||||
onChecked?()
|
onChecked?()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -93,7 +103,7 @@ final class UpdateChecker {
|
|||||||
do {
|
do {
|
||||||
try await downloadAndStage(appcast)
|
try await downloadAndStage(appcast)
|
||||||
availableUpdate = (version: appcast.version, notes: appcast.notes ?? "")
|
availableUpdate = (version: appcast.version, notes: appcast.notes ?? "")
|
||||||
statusMessage = nil
|
statusMessage = manual ? "Update to \(appcast.version) is ready" : nil
|
||||||
} catch UpdateCheckError.checksumMismatch {
|
} catch UpdateCheckError.checksumMismatch {
|
||||||
discardStaging()
|
discardStaging()
|
||||||
availableUpdate = nil
|
availableUpdate = nil
|
||||||
@@ -226,8 +236,11 @@ final class UpdateChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The version recorded in `Redline.app.previous`'s Info.plist, or nil when no
|
/// The version recorded in `Redline.app.previous`'s Info.plist, or nil when no
|
||||||
/// rollback copy exists.
|
/// rollback copy exists. Respects the snapshot-only override for panel rendering.
|
||||||
func previousVersion(target: URL = UpdateChecker.defaultInstallTarget) -> String? {
|
func previousVersion(target: URL = UpdateChecker.defaultInstallTarget) -> String? {
|
||||||
|
if snapshotUsesPreviousVersionOverride {
|
||||||
|
return snapshotPreviousVersionOverride
|
||||||
|
}
|
||||||
let previousURL = target.deletingLastPathComponent().appendingPathComponent("Redline.app.previous")
|
let previousURL = target.deletingLastPathComponent().appendingPathComponent("Redline.app.previous")
|
||||||
let plistURL = previousURL.appendingPathComponent("Contents/Info.plist")
|
let plistURL = previousURL.appendingPathComponent("Contents/Info.plist")
|
||||||
guard let plist = NSDictionary(contentsOf: plistURL) as? [String: Any] else { return nil }
|
guard let plist = NSDictionary(contentsOf: plistURL) as? [String: Any] else { return nil }
|
||||||
|
|||||||
Reference in New Issue
Block a user