mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-08 04:20:07 +02:00
♻️ Reworked updater
This commit is contained in:
@ -205,8 +205,6 @@
|
|||||||
C46B2648298B324100084651 /* ReleaseManifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46B2647298B324100084651 /* ReleaseManifest.swift */; };
|
C46B2648298B324100084651 /* ReleaseManifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46B2647298B324100084651 /* ReleaseManifest.swift */; };
|
||||||
C46B2649298B324100084651 /* ReleaseManifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46B2647298B324100084651 /* ReleaseManifest.swift */; };
|
C46B2649298B324100084651 /* ReleaseManifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46B2647298B324100084651 /* ReleaseManifest.swift */; };
|
||||||
C46B2650298B3C2100084651 /* PHP Monitor Self-Updater.app in Resources */ = {isa = PBXBuildFile; fileRef = C46B264F298B3C2100084651 /* PHP Monitor Self-Updater.app */; };
|
C46B2650298B3C2100084651 /* PHP Monitor Self-Updater.app in Resources */ = {isa = PBXBuildFile; fileRef = C46B264F298B3C2100084651 /* PHP Monitor Self-Updater.app */; };
|
||||||
C46E206D28299B3800D909D6 /* AppUpdateChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */; };
|
|
||||||
C46E206E28299B3800D909D6 /* AppUpdateChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */; };
|
|
||||||
C46E20702829D27F00D909D6 /* AppUpdaterCheckTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206F2829D27F00D909D6 /* AppUpdaterCheckTest.swift */; };
|
C46E20702829D27F00D909D6 /* AppUpdaterCheckTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206F2829D27F00D909D6 /* AppUpdaterCheckTest.swift */; };
|
||||||
C46EBC4428DB95F0007ACC74 /* ShellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46EBC4328DB95F0007ACC74 /* ShellProtocol.swift */; };
|
C46EBC4428DB95F0007ACC74 /* ShellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46EBC4328DB95F0007ACC74 /* ShellProtocol.swift */; };
|
||||||
C46EBC4528DB95F0007ACC74 /* ShellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46EBC4328DB95F0007ACC74 /* ShellProtocol.swift */; };
|
C46EBC4528DB95F0007ACC74 /* ShellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46EBC4328DB95F0007ACC74 /* ShellProtocol.swift */; };
|
||||||
@ -347,7 +345,6 @@
|
|||||||
C471E84628F9BB650021E251 /* InterAppHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EED88827A48778006D7272 /* InterAppHandler.swift */; };
|
C471E84628F9BB650021E251 /* InterAppHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EED88827A48778006D7272 /* InterAppHandler.swift */; };
|
||||||
C471E84728F9BB650021E251 /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
|
C471E84728F9BB650021E251 /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
|
||||||
C471E84828F9BB650021E251 /* EnvironmentCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */; };
|
C471E84828F9BB650021E251 /* EnvironmentCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */; };
|
||||||
C471E84928F9BB650021E251 /* AppUpdateChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */; };
|
|
||||||
C471E84A28F9BB650021E251 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE736282ABA4F00A302C2 /* AppVersion.swift */; };
|
C471E84A28F9BB650021E251 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE736282ABA4F00A302C2 /* AppVersion.swift */; };
|
||||||
C471E84B28F9BB650021E251 /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; };
|
C471E84B28F9BB650021E251 /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; };
|
||||||
C471E84C28F9BB650021E251 /* EnvironmentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A6957528D23EE300A14CF8 /* EnvironmentManager.swift */; };
|
C471E84C28F9BB650021E251 /* EnvironmentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A6957528D23EE300A14CF8 /* EnvironmentManager.swift */; };
|
||||||
@ -437,7 +434,6 @@
|
|||||||
C471E8A928F9BB8F0021E251 /* InterAppHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EED88827A48778006D7272 /* InterAppHandler.swift */; };
|
C471E8A928F9BB8F0021E251 /* InterAppHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EED88827A48778006D7272 /* InterAppHandler.swift */; };
|
||||||
C471E8AA28F9BB8F0021E251 /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
|
C471E8AA28F9BB8F0021E251 /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
|
||||||
C471E8AB28F9BB8F0021E251 /* EnvironmentCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */; };
|
C471E8AB28F9BB8F0021E251 /* EnvironmentCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */; };
|
||||||
C471E8AC28F9BB8F0021E251 /* AppUpdateChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */; };
|
|
||||||
C471E8AD28F9BB8F0021E251 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE736282ABA4F00A302C2 /* AppVersion.swift */; };
|
C471E8AD28F9BB8F0021E251 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE736282ABA4F00A302C2 /* AppVersion.swift */; };
|
||||||
C471E8AE28F9BB8F0021E251 /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; };
|
C471E8AE28F9BB8F0021E251 /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; };
|
||||||
C471E8AF28F9BB8F0021E251 /* EnvironmentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A6957528D23EE300A14CF8 /* EnvironmentManager.swift */; };
|
C471E8AF28F9BB8F0021E251 /* EnvironmentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A6957528D23EE300A14CF8 /* EnvironmentManager.swift */; };
|
||||||
@ -870,7 +866,6 @@
|
|||||||
C469E702294CFDF700A82AB2 /* DomainsListTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainsListTest.swift; sourceTree = "<group>"; };
|
C469E702294CFDF700A82AB2 /* DomainsListTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainsListTest.swift; sourceTree = "<group>"; };
|
||||||
C46B2647298B324100084651 /* ReleaseManifest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseManifest.swift; sourceTree = "<group>"; };
|
C46B2647298B324100084651 /* ReleaseManifest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseManifest.swift; sourceTree = "<group>"; };
|
||||||
C46B264F298B3C2100084651 /* PHP Monitor Self-Updater.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = "PHP Monitor Self-Updater.app"; sourceTree = "<group>"; };
|
C46B264F298B3C2100084651 /* PHP Monitor Self-Updater.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = "PHP Monitor Self-Updater.app"; sourceTree = "<group>"; };
|
||||||
C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateChecker.swift; sourceTree = "<group>"; };
|
|
||||||
C46E206F2829D27F00D909D6 /* AppUpdaterCheckTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUpdaterCheckTest.swift; sourceTree = "<group>"; };
|
C46E206F2829D27F00D909D6 /* AppUpdaterCheckTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUpdaterCheckTest.swift; sourceTree = "<group>"; };
|
||||||
C46EBC4328DB95F0007ACC74 /* ShellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellProtocol.swift; sourceTree = "<group>"; };
|
C46EBC4328DB95F0007ACC74 /* ShellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellProtocol.swift; sourceTree = "<group>"; };
|
||||||
C46EBC4628DB9644007ACC74 /* RealShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealShell.swift; sourceTree = "<group>"; };
|
C46EBC4628DB9644007ACC74 /* RealShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealShell.swift; sourceTree = "<group>"; };
|
||||||
@ -1557,7 +1552,6 @@
|
|||||||
C4EED88827A48778006D7272 /* InterAppHandler.swift */,
|
C4EED88827A48778006D7272 /* InterAppHandler.swift */,
|
||||||
C4D8016522B1584700C6DA1B /* Startup.swift */,
|
C4D8016522B1584700C6DA1B /* Startup.swift */,
|
||||||
C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */,
|
C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */,
|
||||||
C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */,
|
|
||||||
C40FE736282ABA4F00A302C2 /* AppVersion.swift */,
|
C40FE736282ABA4F00A302C2 /* AppVersion.swift */,
|
||||||
C4A6957528D23EE300A14CF8 /* EnvironmentManager.swift */,
|
C4A6957528D23EE300A14CF8 /* EnvironmentManager.swift */,
|
||||||
C409349C298EE8E900D25014 /* AppUpdater.swift */,
|
C409349C298EE8E900D25014 /* AppUpdater.swift */,
|
||||||
@ -2198,7 +2192,6 @@
|
|||||||
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */,
|
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */,
|
||||||
C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */,
|
C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */,
|
||||||
C41CA5ED2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */,
|
C41CA5ED2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */,
|
||||||
C46E206D28299B3800D909D6 /* AppUpdateChecker.swift in Sources */,
|
|
||||||
C412E5FC25700D5300A1FB67 /* HomebrewPackage.swift in Sources */,
|
C412E5FC25700D5300A1FB67 /* HomebrewPackage.swift in Sources */,
|
||||||
03E36FE728D9219000636F7F /* ActiveShell.swift in Sources */,
|
03E36FE728D9219000636F7F /* ActiveShell.swift in Sources */,
|
||||||
C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */,
|
C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */,
|
||||||
@ -2302,7 +2295,6 @@
|
|||||||
C471E84628F9BB650021E251 /* InterAppHandler.swift in Sources */,
|
C471E84628F9BB650021E251 /* InterAppHandler.swift in Sources */,
|
||||||
C471E84728F9BB650021E251 /* Startup.swift in Sources */,
|
C471E84728F9BB650021E251 /* Startup.swift in Sources */,
|
||||||
C471E84828F9BB650021E251 /* EnvironmentCheck.swift in Sources */,
|
C471E84828F9BB650021E251 /* EnvironmentCheck.swift in Sources */,
|
||||||
C471E84928F9BB650021E251 /* AppUpdateChecker.swift in Sources */,
|
|
||||||
C471E84A28F9BB650021E251 /* AppVersion.swift in Sources */,
|
C471E84A28F9BB650021E251 /* AppVersion.swift in Sources */,
|
||||||
C471E84B28F9BB650021E251 /* ServicesManager.swift in Sources */,
|
C471E84B28F9BB650021E251 /* ServicesManager.swift in Sources */,
|
||||||
C471E84C28F9BB650021E251 /* EnvironmentManager.swift in Sources */,
|
C471E84C28F9BB650021E251 /* EnvironmentManager.swift in Sources */,
|
||||||
@ -2472,7 +2464,6 @@
|
|||||||
C471E8A928F9BB8F0021E251 /* InterAppHandler.swift in Sources */,
|
C471E8A928F9BB8F0021E251 /* InterAppHandler.swift in Sources */,
|
||||||
C471E8AA28F9BB8F0021E251 /* Startup.swift in Sources */,
|
C471E8AA28F9BB8F0021E251 /* Startup.swift in Sources */,
|
||||||
C471E8AB28F9BB8F0021E251 /* EnvironmentCheck.swift in Sources */,
|
C471E8AB28F9BB8F0021E251 /* EnvironmentCheck.swift in Sources */,
|
||||||
C471E8AC28F9BB8F0021E251 /* AppUpdateChecker.swift in Sources */,
|
|
||||||
C471E8AD28F9BB8F0021E251 /* AppVersion.swift in Sources */,
|
C471E8AD28F9BB8F0021E251 /* AppVersion.swift in Sources */,
|
||||||
C471E8AE28F9BB8F0021E251 /* ServicesManager.swift in Sources */,
|
C471E8AE28F9BB8F0021E251 /* ServicesManager.swift in Sources */,
|
||||||
C471E8AF28F9BB8F0021E251 /* EnvironmentManager.swift in Sources */,
|
C471E8AF28F9BB8F0021E251 /* EnvironmentManager.swift in Sources */,
|
||||||
@ -2795,7 +2786,6 @@
|
|||||||
C46EBC4B28DB966A007ACC74 /* TestableShell.swift in Sources */,
|
C46EBC4B28DB966A007ACC74 /* TestableShell.swift in Sources */,
|
||||||
C40FE73B282ABB2E00A302C2 /* AppVersionTest.swift in Sources */,
|
C40FE73B282ABB2E00A302C2 /* AppVersionTest.swift in Sources */,
|
||||||
C4F780C625D80B75000DBC97 /* XibLoadable.swift in Sources */,
|
C4F780C625D80B75000DBC97 /* XibLoadable.swift in Sources */,
|
||||||
C46E206E28299B3800D909D6 /* AppUpdateChecker.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -1,228 +0,0 @@
|
|||||||
//
|
|
||||||
// Updater.swift
|
|
||||||
// PHP Monitor
|
|
||||||
//
|
|
||||||
// Created by Nico Verbruggen on 09/05/2022.
|
|
||||||
// Copyright © 2023 Nico Verbruggen. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import AppKit
|
|
||||||
|
|
||||||
class AppUpdateChecker {
|
|
||||||
|
|
||||||
public static var latestCaskFileContents: String = ""
|
|
||||||
|
|
||||||
public static var enabled: Bool = {
|
|
||||||
return Preferences.isEnabled(.automaticBackgroundUpdateCheck)
|
|
||||||
}()
|
|
||||||
|
|
||||||
public static var isDev: Bool = {
|
|
||||||
return App.version.contains("-dev")
|
|
||||||
}()
|
|
||||||
|
|
||||||
public static func retrieveVersionFromCask(
|
|
||||||
_ initiatedFromBackground: Bool = true
|
|
||||||
) async -> String {
|
|
||||||
let caskFile = App.version.contains("-dev")
|
|
||||||
? Constants.Urls.DevBuildCaskFile.absoluteString
|
|
||||||
: Constants.Urls.StableBuildCaskFile.absoluteString
|
|
||||||
|
|
||||||
var command = "curl -s"
|
|
||||||
|
|
||||||
if initiatedFromBackground {
|
|
||||||
command = "curl -s --max-time 5"
|
|
||||||
}
|
|
||||||
|
|
||||||
AppUpdateChecker.latestCaskFileContents = await Shell.pipe("\(command) '\(caskFile)'").out
|
|
||||||
return await Shell.pipe("echo \"\(Self.latestCaskFileContents)\" | grep version").out
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func checkIfNewerVersionIsAvailable(
|
|
||||||
initiatedFromBackground: Bool = true
|
|
||||||
) async {
|
|
||||||
if initiatedFromBackground {
|
|
||||||
if !Preferences.isEnabled(.automaticBackgroundUpdateCheck) {
|
|
||||||
Log.info("Automatic updates are disabled. No check will be performed.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.info("Automatic updates are enabled, a check will be performed.")
|
|
||||||
}
|
|
||||||
|
|
||||||
let versionString = await retrieveVersionFromCask(initiatedFromBackground)
|
|
||||||
|
|
||||||
guard let onlineVersion = AppVersion.from(versionString) else {
|
|
||||||
Log.err("We couldn't check for updates!")
|
|
||||||
|
|
||||||
// Only notify about connection issues if the request to check for updates was explicit
|
|
||||||
if !initiatedFromBackground {
|
|
||||||
notifyAboutConnectionIssue()
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentVersion = AppVersion.fromCurrentVersion()
|
|
||||||
|
|
||||||
handleVersionComparison(
|
|
||||||
currentVersion,
|
|
||||||
onlineVersion,
|
|
||||||
initiatedFromBackground
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func handleVersionComparison(
|
|
||||||
_ currentVersion: AppVersion,
|
|
||||||
_ onlineVersion: AppVersion,
|
|
||||||
_ background: Bool
|
|
||||||
) {
|
|
||||||
// TODO: Restore original behaviour
|
|
||||||
notifyAboutNewerVersion(version: onlineVersion)
|
|
||||||
return
|
|
||||||
|
|
||||||
switch onlineVersion.version.versionCompare(currentVersion.version) {
|
|
||||||
case .orderedAscending:
|
|
||||||
Log.info("You are running a newer version of PHP Monitor "
|
|
||||||
+ "(\(currentVersion.computerReadable) > \(onlineVersion.computerReadable)).")
|
|
||||||
if !background { notifyVersionDoesNotNeedUpgrade() }
|
|
||||||
case .orderedDescending:
|
|
||||||
Log.info("There is a newer version (\(onlineVersion)) available! "
|
|
||||||
+ "(\(onlineVersion.computerReadable) > \(currentVersion.computerReadable))")
|
|
||||||
notifyAboutNewerVersion(version: onlineVersion)
|
|
||||||
case .orderedSame:
|
|
||||||
if currentVersion.build != nil
|
|
||||||
&& onlineVersion.build != nil
|
|
||||||
&& buildDiffers(currentVersion, onlineVersion, background) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.info("The installed version (\(currentVersion.computerReadable)) matches the latest release "
|
|
||||||
+ "(\(onlineVersion.computerReadable)).")
|
|
||||||
if !background { notifyVersionDoesNotNeedUpgrade() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func buildDiffers(
|
|
||||||
_ currentVersion: AppVersion,
|
|
||||||
_ onlineVersion: AppVersion,
|
|
||||||
_ background: Bool
|
|
||||||
) -> Bool {
|
|
||||||
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 onlineVersion.build! < currentVersion.build! {
|
|
||||||
Log.info("You are running a newer build of PHP Monitor "
|
|
||||||
+ "(\(currentVersion.computerReadable) > \(onlineVersion.computerReadable)).")
|
|
||||||
if !background { notifyVersionDoesNotNeedUpgrade() }
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func notifyVersionDoesNotNeedUpgrade() {
|
|
||||||
Task { @MainActor in
|
|
||||||
BetterAlert().withInformation(
|
|
||||||
title: "updater.alerts.is_latest_version.title".localized,
|
|
||||||
subtitle: "updater.alerts.is_latest_version.subtitle".localized(App.shortVersion),
|
|
||||||
description: ""
|
|
||||||
)
|
|
||||||
.withPrimary(text: "generic.ok".localized)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func notifyAboutNewerVersion(version: AppVersion) {
|
|
||||||
let devSuffix = isDev ? "-dev" : ""
|
|
||||||
let command = isDev ? "brew upgrade phpmon-dev" : "brew upgrade phpmon"
|
|
||||||
|
|
||||||
Task { @MainActor in
|
|
||||||
BetterAlert().withInformation(
|
|
||||||
title: "updater.alerts.newer_version_available.title".localized(version.humanReadable),
|
|
||||||
subtitle: "updater.alerts.newer_version_available.subtitle".localized,
|
|
||||||
description: HomebrewDiagnostics.customCaskInstalled
|
|
||||||
? "updater.installation_source.brew".localized(command)
|
|
||||||
: "updater.installation_source.direct".localized
|
|
||||||
)
|
|
||||||
.withPrimary(
|
|
||||||
text: "updater.alerts.buttons.install".localized,
|
|
||||||
action: { vc in
|
|
||||||
Self.installUpdate()
|
|
||||||
vc.close(with: .OK)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.withSecondary(
|
|
||||||
text: "updater.alerts.buttons.release_notes".localized,
|
|
||||||
action: { vc in
|
|
||||||
vc.close(with: .OK)
|
|
||||||
|
|
||||||
NSWorkspace.shared.open(
|
|
||||||
Constants.Urls.GitHubReleases.appendingPathComponent("/tag/v\(version.tagged)\(devSuffix)")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.withTertiary(text: "Dismiss", action: { vc in
|
|
||||||
vc.close(with: .OK)
|
|
||||||
})
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func installUpdate() {
|
|
||||||
let updater = Bundle.main.resourceURL!.path + "/PHP Monitor Self-Updater.app"
|
|
||||||
|
|
||||||
system_quiet("mkdir -p ~/.config/phpmon/updater 2> /dev/null")
|
|
||||||
|
|
||||||
let updaterDirectory = "~/.config/phpmon/updater"
|
|
||||||
.replacingOccurrences(of: "~", with: NSHomeDirectory())
|
|
||||||
|
|
||||||
system_quiet("cp -R \"\(updater)\" \"\(updaterDirectory)/PHP Monitor Self-Updater.app\"")
|
|
||||||
|
|
||||||
let sha256 = system("echo \"\(Self.latestCaskFileContents)\" | grep sha256")
|
|
||||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
||||||
.replacingOccurrences(of: "'", with: "")
|
|
||||||
.split(separator: " ").last ?? ""
|
|
||||||
|
|
||||||
let url = system("echo \"\(Self.latestCaskFileContents)\" | grep url")
|
|
||||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
||||||
.replacingOccurrences(of: "'", with: "")
|
|
||||||
.split(separator: " ").last ?? ""
|
|
||||||
|
|
||||||
try! FileSystem.writeAtomicallyToFile(
|
|
||||||
"\(updaterDirectory)/update.json",
|
|
||||||
content: """
|
|
||||||
{ "url": "\(url)", "sha256": "\(sha256)" }
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
let updaterUrl = NSURL(fileURLWithPath: updater, isDirectory: true) as URL
|
|
||||||
let configuration = NSWorkspace.OpenConfiguration()
|
|
||||||
NSWorkspace.shared.openApplication(at: updaterUrl, configuration: configuration) { _, _ in
|
|
||||||
print("The updater has been launched successfully!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func notifyAboutConnectionIssue() {
|
|
||||||
Task { @MainActor in
|
|
||||||
BetterAlert().withInformation(
|
|
||||||
title: "updater.alerts.cannot_check_for_update.title".localized,
|
|
||||||
subtitle: "updater.alerts.cannot_check_for_update.subtitle".localized,
|
|
||||||
description: "updater.alerts.cannot_check_for_update.description".localized(
|
|
||||||
App.version
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.withTertiary(
|
|
||||||
text: "updater.alerts.buttons.releases_on_github".localized,
|
|
||||||
action: { _ in
|
|
||||||
NSWorkspace.shared.open(Constants.Urls.GitHubReleases)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.withPrimary(text: "generic.ok".localized)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -7,75 +7,160 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
class AppUpdater {
|
class AppUpdater {
|
||||||
|
var caskFile: CaskFile!
|
||||||
|
var latestVersionOnline: AppVersion!
|
||||||
|
var interactive: Bool = false
|
||||||
|
|
||||||
public func checkForUpdates(background: Bool) async {
|
public func checkForUpdates(interactive: Bool) async {
|
||||||
if background && !Preferences.isEnabled(.automaticBackgroundUpdateCheck) {
|
self.interactive = interactive
|
||||||
|
|
||||||
|
if interactive && !Preferences.isEnabled(.automaticBackgroundUpdateCheck) {
|
||||||
Log.info("Skipping automatic update check due to user preference.")
|
Log.info("Skipping automatic update check due to user preference.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info("The app will search for updates...")
|
Log.info("The app will search for updates...")
|
||||||
|
|
||||||
let caskUrl = App.version.contains("-dev")
|
let caskUrl = App.identifier.contains(".dev")
|
||||||
? Constants.Urls.DevBuildCaskFile
|
? Constants.Urls.DevBuildCaskFile
|
||||||
: Constants.Urls.StableBuildCaskFile
|
: Constants.Urls.StableBuildCaskFile
|
||||||
|
|
||||||
guard let caskFile = await CaskFile.from(url: caskUrl) else {
|
guard let caskFile = await CaskFile.from(url: caskUrl) else {
|
||||||
Log.err("The contents of the CaskFile at '\(caskUrl.absoluteString)' could not be retrieved.")
|
Log.err("The contents of the CaskFile at '\(caskUrl.absoluteString)' could not be retrieved.")
|
||||||
|
return presentCouldNotRetrieveUpdateIfInteractive()
|
||||||
|
}
|
||||||
|
|
||||||
if !background {
|
self.caskFile = caskFile
|
||||||
|
|
||||||
|
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 presentCouldNotRetrieveUpdateIfInteractive()
|
||||||
|
}
|
||||||
|
|
||||||
|
latestVersionOnline = onlineVersion
|
||||||
|
Log.info("The latest version read from '\(caskUrl.lastPathComponent)' is: v\(onlineVersion.computerReadable).")
|
||||||
|
|
||||||
|
if latestVersionOnline > currentVersion {
|
||||||
|
presentNewerVersionAvailableAlert()
|
||||||
|
} else if interactive {
|
||||||
|
presentNoNewerVersionAvailableAlert()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func presentCouldNotRetrieveUpdateIfInteractive() {
|
||||||
|
if interactive {
|
||||||
return presentCouldNotRetrieveUpdate()
|
return presentCouldNotRetrieveUpdate()
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.caskFile = caskFile
|
// MARK: - Alerts
|
||||||
|
|
||||||
if newerVersionExists() {
|
|
||||||
presentNewerVersionAvailableAlert()
|
|
||||||
} else {
|
|
||||||
if !background {
|
|
||||||
presentNoNewerVersionAvailableAlert()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
public func presentNewerVersionAvailableAlert() {
|
||||||
print("A newer version is available")
|
let command = App.identifier.contains(".dev")
|
||||||
|
? "brew upgrade phpmon-dev"
|
||||||
|
: "brew upgrade phpmon"
|
||||||
|
|
||||||
|
Task { @MainActor in
|
||||||
|
BetterAlert().withInformation(
|
||||||
|
title: "updater.alerts.newer_version_available.title"
|
||||||
|
.localized(latestVersionOnline.humanReadable),
|
||||||
|
subtitle: "updater.alerts.newer_version_available.subtitle"
|
||||||
|
.localized,
|
||||||
|
description: HomebrewDiagnostics.customCaskInstalled
|
||||||
|
? "updater.installation_source.brew".localized(command)
|
||||||
|
: "updater.installation_source.direct".localized
|
||||||
|
)
|
||||||
|
.withPrimary(
|
||||||
|
text: "updater.alerts.buttons.install".localized,
|
||||||
|
action: { vc in
|
||||||
|
self.prepareForDownload()
|
||||||
|
vc.close(with: .OK)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.withSecondary(
|
||||||
|
text: "updater.alerts.buttons.release_notes".localized,
|
||||||
|
action: { _ in
|
||||||
|
let urlSegments = self.caskFile.url.split(separator: "/")
|
||||||
|
let tag = urlSegments[urlSegments.count - 2] // ../download/{tag}/{file.zip}
|
||||||
|
NSWorkspace.shared.open(
|
||||||
|
Constants.Urls.GitHubReleases.appendingPathComponent("/tag/\(tag)")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.withTertiary(text: "updater.alerts.buttons.dismiss".localized, action: { vc in
|
||||||
|
vc.close(with: .OK)
|
||||||
|
})
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func presentNoNewerVersionAvailableAlert() {
|
public func presentNoNewerVersionAvailableAlert() {
|
||||||
print("No newer version is available")
|
Task { @MainActor in
|
||||||
|
BetterAlert().withInformation(
|
||||||
|
title: "updater.alerts.is_latest_version.title".localized,
|
||||||
|
subtitle: "updater.alerts.is_latest_version.subtitle".localized(App.shortVersion),
|
||||||
|
description: ""
|
||||||
|
)
|
||||||
|
.withPrimary(text: "generic.ok".localized)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func presentCouldNotRetrieveUpdate() {
|
public func presentCouldNotRetrieveUpdate() {
|
||||||
print("Could not retrieve update")
|
Task { @MainActor in
|
||||||
|
BetterAlert().withInformation(
|
||||||
|
title: "updater.alerts.cannot_check_for_update.title".localized,
|
||||||
|
subtitle: "updater.alerts.cannot_check_for_update.subtitle".localized,
|
||||||
|
description: "updater.alerts.cannot_check_for_update.description".localized(
|
||||||
|
App.version
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.withTertiary(
|
||||||
|
text: "updater.alerts.buttons.releases_on_github".localized,
|
||||||
|
action: { _ in
|
||||||
|
NSWorkspace.shared.open(Constants.Urls.GitHubReleases)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
.withPrimary(text: "generic.ok".localized)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Preparing for Self-Updater
|
||||||
|
|
||||||
private func prepareForDownload() {
|
private func prepareForDownload() {
|
||||||
|
let updater = Bundle.main.resourceURL!.path + "/PHP Monitor Self-Updater.app"
|
||||||
|
|
||||||
|
system_quiet("mkdir -p ~/.config/phpmon/updater 2> /dev/null")
|
||||||
|
|
||||||
|
let updaterDirectory = "~/.config/phpmon/updater"
|
||||||
|
.replacingOccurrences(of: "~", with: NSHomeDirectory())
|
||||||
|
|
||||||
|
system_quiet("cp -R \"\(updater)\" \"\(updaterDirectory)/PHP Monitor Self-Updater.app\"")
|
||||||
|
|
||||||
|
try! FileSystem.writeAtomicallyToFile(
|
||||||
|
"\(updaterDirectory)/update.json",
|
||||||
|
content: "{ \"url\": \"\(caskFile.url)\", \"sha256\": \"\(caskFile.sha256)\" }"
|
||||||
|
)
|
||||||
|
|
||||||
|
let updaterUrl = NSURL(fileURLWithPath: updater, isDirectory: true) as URL
|
||||||
|
let configuration = NSWorkspace.OpenConfiguration()
|
||||||
|
|
||||||
|
NSWorkspace.shared.openApplication(at: updaterUrl, configuration: configuration) { _, _ in
|
||||||
|
Log.info("The updater has been launched successfully!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func checkIfUpgradeWasPerformed() {
|
// MARK: - Checking if Self-Updater Worked
|
||||||
|
|
||||||
|
public static func checkIfUpdateWasPerformed() {
|
||||||
if FileSystem.fileExists("~/.config/phpmon/updater/upgrade.success") {
|
if FileSystem.fileExists("~/.config/phpmon/updater/upgrade.success") {
|
||||||
// Send a notification about the update
|
// Send a notification about the update
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
|
@ -87,7 +87,7 @@ class AppVersion: Comparable {
|
|||||||
static func < (lhs: AppVersion, rhs: AppVersion) -> Bool {
|
static func < (lhs: AppVersion, rhs: AppVersion) -> Bool {
|
||||||
let comparisonResult = lhs.version.versionCompare(rhs.version)
|
let comparisonResult = lhs.version.versionCompare(rhs.version)
|
||||||
|
|
||||||
if comparisonResult == .orderedDescending {
|
if comparisonResult == .orderedAscending {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,5 +75,4 @@ struct CaskFile {
|
|||||||
|
|
||||||
return CaskFile(properties: props)
|
return CaskFile(properties: props)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -112,10 +112,7 @@ extension MainMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// await AppUpdateChecker.checkIfNewerVersionIsAvailable()
|
await AppUpdater().checkForUpdates(interactive: false)
|
||||||
await AppUpdater().checkForUpdates(background: true)
|
|
||||||
|
|
||||||
exit(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the linked version has changed between launches of phpmon
|
// Check if the linked version has changed between launches of phpmon
|
||||||
@ -125,7 +122,7 @@ extension MainMenu {
|
|||||||
Log.info("PHP Monitor is ready to serve!")
|
Log.info("PHP Monitor is ready to serve!")
|
||||||
|
|
||||||
// Check if we upgraded just now
|
// Check if we upgraded just now
|
||||||
AppUpdater.checkIfUpgradeWasPerformed()
|
AppUpdater.checkIfUpdateWasPerformed()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -199,7 +199,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func checkForUpdates() {
|
@objc func checkForUpdates() {
|
||||||
Task { await AppUpdateChecker.checkIfNewerVersionIsAvailable(initiatedFromBackground: false) }
|
Task { await AppUpdater().checkForUpdates(interactive: true) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Menu Delegate
|
// MARK: - Menu Delegate
|
||||||
|
@ -623,8 +623,8 @@ COMMON TROUBLESHOOTING TIPS
|
|||||||
|
|
||||||
"updater.alerts.newer_version_available.title" = "PHP Monitor v%@ is now available!";
|
"updater.alerts.newer_version_available.title" = "PHP Monitor v%@ is now available!";
|
||||||
"updater.alerts.newer_version_available.subtitle" = "Keeping PHP Monitor up-to-date is highly recommended, since newer versions usually fix bugs and include fixes to support the latest versions of Valet and PHP.";
|
"updater.alerts.newer_version_available.subtitle" = "Keeping PHP Monitor up-to-date is highly recommended, since newer versions usually fix bugs and include fixes to support the latest versions of Valet and PHP.";
|
||||||
"updater.installation_source.brew" = "The recommended method of installing updates to PHP Monitor is to simply press 'Install Update'. This will launch the separate PHP Monitor Self-Updater, which will update the app. You may also upgrade via the terminal by running `%@`.";
|
"updater.installation_source.brew" = "The recommended method of installing updates to PHP Monitor is to simply press 'Install Update'.\n\n(You may also upgrade via the terminal by running `%@`, but this is not recommended.)";
|
||||||
"updater.installation_source.direct" = "The recommended method of installing updates to PHP Monitor is to simply press 'Install Update'. This will launch the separate PHP Monitor Self-Updater, which will update the app.";
|
"updater.installation_source.direct" = "The recommended method of installing updates to PHP Monitor is to simply press 'Install Update'.";
|
||||||
"updater.alerts.buttons.release_notes" = "View Release Notes";
|
"updater.alerts.buttons.release_notes" = "View Release Notes";
|
||||||
|
|
||||||
"updater.alerts.is_latest_version.title" = "PHP Monitor is up-to-date!";
|
"updater.alerts.is_latest_version.title" = "PHP Monitor is up-to-date!";
|
||||||
@ -635,6 +635,7 @@ COMMON TROUBLESHOOTING TIPS
|
|||||||
"updater.alerts.cannot_check_for_update.description" = "The currently installed version is: %@. You can go to the list of the latest releases (on GitHub) by clicking on the button on the left.";
|
"updater.alerts.cannot_check_for_update.description" = "The currently installed version is: %@. You can go to the list of the latest releases (on GitHub) by clicking on the button on the left.";
|
||||||
"updater.alerts.buttons.releases_on_github" = "View Releases";
|
"updater.alerts.buttons.releases_on_github" = "View Releases";
|
||||||
"updater.alerts.buttons.install" = "Install Update";
|
"updater.alerts.buttons.install" = "Install Update";
|
||||||
|
"updater.alerts.buttons.dismiss" = "Dismiss";
|
||||||
|
|
||||||
// WARNINGS ABOUT NON-DEFAULT TLD
|
// WARNINGS ABOUT NON-DEFAULT TLD
|
||||||
|
|
||||||
|
@ -49,4 +49,5 @@ class CaskFileParserTest: XCTestCase {
|
|||||||
XCTAssertTrue(caskFile.properties.keys.contains("url"))
|
XCTAssertTrue(caskFile.properties.keys.contains("url"))
|
||||||
XCTAssertTrue(caskFile.properties.keys.contains("appcast"))
|
XCTAssertTrue(caskFile.properties.keys.contains("appcast"))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -60,21 +60,17 @@ class AppVersionTest: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func test_can_compare_version_numbers() {
|
func test_can_compare_version_numbers() {
|
||||||
var first = AppVersion.from("5.0_100")!
|
// Build is newer
|
||||||
var second = AppVersion.from("5.0_101")!
|
XCTAssertTrue(AppVersion.from("5.0_101")! > AppVersion.from("5.0_100")!)
|
||||||
XCTAssertTrue(second > first)
|
|
||||||
|
|
||||||
first = AppVersion.from("5.0_100")!
|
// Version and build is the same
|
||||||
second = AppVersion.from("5.0_100")!
|
XCTAssertFalse(AppVersion.from("5.0.0_100")! > AppVersion.from("5.0_100")!)
|
||||||
XCTAssertFalse(second > first)
|
|
||||||
|
|
||||||
first = AppVersion.from("5.0_100")!
|
// Version is newer
|
||||||
second = AppVersion.from("5.0.1_100")!
|
XCTAssertTrue(AppVersion.from("5.1_100")! > AppVersion.from("5.0_100")!)
|
||||||
XCTAssertFalse(second > first)
|
|
||||||
|
|
||||||
first = AppVersion.from("5.0_102")!
|
// Build is older
|
||||||
second = AppVersion.from("5.0_101")!
|
XCTAssertFalse(AppVersion.from("5.0_101")! > AppVersion.from("5.0_102")!)
|
||||||
XCTAssertFalse(second > first)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user