diff --git a/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor DEV.xcscheme b/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor DEV.xcscheme index fad7a23..4b4f8a9 100644 --- a/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor DEV.xcscheme +++ b/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor DEV.xcscheme @@ -91,7 +91,7 @@ + isEnabled = "NO"> + isEnabled = "NO"> Bool { - if Int(onlineVersion.build!)! > Int(currentVersion.build!)! { + if onlineVersion.build! > currentVersion.build! { Log.info("There is a newer build of PHP Monitor available! " + "(\(onlineVersion.computerReadable) > \(currentVersion.computerReadable))") notifyAboutNewerVersion(version: onlineVersion) return true - } else if Int(onlineVersion.build!)! < Int(currentVersion.build!)! { + } else if onlineVersion.build! < currentVersion.build! { Log.info("You are running a newer build of PHP Monitor " + "(\(currentVersion.computerReadable) > \(onlineVersion.computerReadable)).") if !background { notifyVersionDoesNotNeedUpgrade() } diff --git a/phpmon/Domain/App/AppUpdater.swift b/phpmon/Domain/App/AppUpdater.swift index a214c42..4517e5e 100644 --- a/phpmon/Domain/App/AppUpdater.swift +++ b/phpmon/Domain/App/AppUpdater.swift @@ -10,15 +10,26 @@ import Foundation class AppUpdater { - var caskFile: CaskFile? + public func checkForUpdates(background: Bool) async { + if background && !Preferences.isEnabled(.automaticBackgroundUpdateCheck) { + Log.info("Skipping automatic update check due to user preference.") + return + } - public func checkForUpdates(background: Bool) { - guard let caskFile = CaskFile.from( - url: App.version.contains("-dev") + Log.info("The app will search for updates...") + + let caskUrl = App.version.contains("-dev") ? Constants.Urls.DevBuildCaskFile : Constants.Urls.StableBuildCaskFile - ) else { - return presentCouldNotRetrieveUpdate() + + guard let caskFile = await CaskFile.from(url: caskUrl) else { + Log.err("The contents of the CaskFile at '\(caskUrl.absoluteString)' could not be retrieved.") + + if !background { + return presentCouldNotRetrieveUpdate() + } else { + return + } } self.caskFile = caskFile @@ -32,24 +43,49 @@ class AppUpdater { } } + var caskFile: CaskFile! + public func newerVersionExists() -> Bool { + let currentVersion = AppVersion.fromCurrentVersion() + + guard let onlineVersion = AppVersion.from(caskFile.version) else { + Log.err("The version string from the CaskFile could not be read.") + return false + } + + Log.info("You are running \(currentVersion.computerReadable). The latest version is: \(onlineVersion.computerReadable).") + // Do the comparison w/ current version return true } public func presentNewerVersionAvailableAlert() { - + print("A newer version is available") } public func presentNoNewerVersionAvailableAlert() { - + print("No newer version is available") } public func presentCouldNotRetrieveUpdate() { - + print("Could not retrieve update") } private func prepareForDownload() { } + + public static func checkIfUpgradeWasPerformed() { + if FileSystem.fileExists("~/.config/phpmon/updater/upgrade.success") { + // Send a notification about the update + Task { @MainActor in + LocalNotification.send( + title: "notification.phpmon_updated.title".localized, + subtitle: "notification.phpmon_updated.desc".localized(App.shortVersion), + preference: nil + ) + try! FileSystem.remove("~/.config/phpmon/updater/upgrade.success") + } + } + } } diff --git a/phpmon/Domain/App/AppVersion.swift b/phpmon/Domain/App/AppVersion.swift index 62231b4..04d0f69 100644 --- a/phpmon/Domain/App/AppVersion.swift +++ b/phpmon/Domain/App/AppVersion.swift @@ -8,14 +8,14 @@ import Foundation -class AppVersion { +class AppVersion: Comparable { var version: String - var build: String? + var build: Int? var suffix: String? init(version: String, build: String?, suffix: String? = nil) { self.version = version - self.build = build + self.build = Int(build ?? "0") self.suffix = suffix } @@ -75,11 +75,27 @@ class AppVersion { } var computerReadable: String { - return "\(version)_\(build ?? "0")" + return "\(version)_\(build ?? 0)" } var humanReadable: String { - return "\(version) (\(build ?? "???"))" + return "\(version) (\(build ?? 0))" } + // MARK: - Comparable Protocol + + static func < (lhs: AppVersion, rhs: AppVersion) -> Bool { + let comparisonResult = lhs.version.versionCompare(rhs.version) + + if comparisonResult == .orderedDescending { + return true + } + + return lhs.build ?? 0 < rhs.build ?? 0 + } + + static func == (lhs: AppVersion, rhs: AppVersion) -> Bool { + lhs.version.versionCompare(rhs.version) == .orderedSame + && lhs.build == rhs.build + } } diff --git a/phpmon/Domain/Integrations/Homebrew/CaskFile.swift b/phpmon/Domain/Integrations/Homebrew/CaskFile.swift index c3f916d..c1ebea1 100644 --- a/phpmon/Domain/Integrations/Homebrew/CaskFile.swift +++ b/phpmon/Domain/Integrations/Homebrew/CaskFile.swift @@ -24,8 +24,14 @@ struct CaskFile { return self.properties["version"]! } - public static func from(url: URL) -> CaskFile? { - let string = try? String(contentsOf: url) + public static func from(url: URL) async -> CaskFile? { + var string: String? + + if url.scheme == "file" { + string = try? String(contentsOf: url) + } else { + string = await Shell.pipe("curl -s --max-time 10 '\(url.absoluteString)'").out + } guard let string else { Log.err("The content of the URL for the CaskFile could not be retrieved") diff --git a/phpmon/Domain/Menu/MainMenu+Startup.swift b/phpmon/Domain/Menu/MainMenu+Startup.swift index 5df6eab..c25bebe 100644 --- a/phpmon/Domain/Menu/MainMenu+Startup.swift +++ b/phpmon/Domain/Menu/MainMenu+Startup.swift @@ -112,7 +112,10 @@ extension MainMenu { } } - await AppUpdateChecker.checkIfNewerVersionIsAvailable() + // await AppUpdateChecker.checkIfNewerVersionIsAvailable() + await AppUpdater().checkForUpdates(background: true) + + exit(0) } // Check if the linked version has changed between launches of phpmon @@ -122,7 +125,7 @@ extension MainMenu { Log.info("PHP Monitor is ready to serve!") // Check if we upgraded just now - // self.checkIfUpgradeWasPerformed() + AppUpdater.checkIfUpgradeWasPerformed() } /** @@ -191,18 +194,4 @@ extension MainMenu { Log.info("Detected applications: \(appNames)") } - - private func checkIfUpgradeWasPerformed() { - if FileSystem.fileExists("~/.config/phpmon/updater/upgrade.success") { - // Send a notification about the update - Task { @MainActor in - LocalNotification.send( - title: "notification.phpmon_updated.title".localized, - subtitle: "notification.phpmon_updated.desc".localized(App.shortVersion), - preference: nil - ) - try! FileSystem.remove("~/.config/phpmon/updater/upgrade.success") - } - } - } } diff --git a/tests/unit/Parsers/CaskFileParserTest.swift b/tests/unit/Parsers/CaskFileParserTest.swift index 314c473..df065d3 100644 --- a/tests/unit/Parsers/CaskFileParserTest.swift +++ b/tests/unit/Parsers/CaskFileParserTest.swift @@ -16,8 +16,8 @@ class CaskFileParserTest: XCTestCase { .url(forResource: "phpmon-dev", withExtension: "rb")! } - func test_can_extract_fields_from_cask_file() throws { - guard let caskFile = CaskFile.from(url: CaskFileParserTest.exampleFilePath) else { + func test_can_extract_fields_from_cask_file() async throws { + guard let caskFile = await CaskFile.from(url: CaskFileParserTest.exampleFilePath) else { return XCTFail("The CaskFile could not be parsed, check the log for more info") } @@ -39,8 +39,8 @@ class CaskFileParserTest: XCTestCase { ) } - func test_can_extract_fields_from_remote_cask_file() throws { - guard let caskFile = CaskFile.from(url: Constants.Urls.StableBuildCaskFile) else { + func test_can_extract_fields_from_remote_cask_file() async throws { + guard let caskFile = await CaskFile.from(url: Constants.Urls.StableBuildCaskFile) else { return XCTFail("The remote CaskFile could not be parsed, check the log for more info") } diff --git a/tests/unit/Versions/AppVersionTest.swift b/tests/unit/Versions/AppVersionTest.swift index c2ac087..1ff9836 100644 --- a/tests/unit/Versions/AppVersionTest.swift +++ b/tests/unit/Versions/AppVersionTest.swift @@ -28,7 +28,7 @@ class AppVersionTest: XCTestCase { XCTAssertNotNil(version) XCTAssertEqual("1.0.0", version?.version) - XCTAssertEqual("600", version?.build) + XCTAssertEqual(600, version?.build) XCTAssertEqual(nil, version?.suffix) } @@ -46,7 +46,7 @@ class AppVersionTest: XCTestCase { XCTAssertNotNil(version) XCTAssertEqual("1.0.0", version?.version) - XCTAssertEqual("870", version?.build) + XCTAssertEqual(870, version?.build) XCTAssertEqual("dev", version?.suffix) } @@ -55,8 +55,26 @@ class AppVersionTest: XCTestCase { XCTAssertNotNil(version) XCTAssertEqual("1.0.0", version?.version) - XCTAssertEqual("870", version?.build) + XCTAssertEqual(870, version?.build) XCTAssertEqual("dev", version?.suffix) } + func test_can_compare_version_numbers() { + var first = AppVersion.from("5.0_100")! + var second = AppVersion.from("5.0_101")! + XCTAssertTrue(second > first) + + first = AppVersion.from("5.0_100")! + second = AppVersion.from("5.0_100")! + XCTAssertFalse(second > first) + + first = AppVersion.from("5.0_100")! + second = AppVersion.from("5.0.1_100")! + XCTAssertFalse(second > first) + + first = AppVersion.from("5.0_102")! + second = AppVersion.from("5.0_101")! + XCTAssertFalse(second > first) + } + }