mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 12:00:09 +02:00
🏗 WIP: Check for updates
This commit is contained in:
@ -117,6 +117,8 @@
|
||||
C464ADAF275A7A69003FCD53 /* DomainListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAE275A7A69003FCD53 /* DomainListVC.swift */; };
|
||||
C464ADB0275A7A6A003FCD53 /* DomainListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAE275A7A69003FCD53 /* DomainListVC.swift */; };
|
||||
C464ADB2275A87CA003FCD53 /* DomainListCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADB1275A87CA003FCD53 /* DomainListCellProtocol.swift */; };
|
||||
C46E206D28299B3800D909D6 /* Updater.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206C28299B3800D909D6 /* Updater.swift */; };
|
||||
C46E206E28299B3800D909D6 /* Updater.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206C28299B3800D909D6 /* Updater.swift */; };
|
||||
C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA23E246C358E00944F05 /* StringExtension.swift */; };
|
||||
C473319F2470923A009A0597 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C473319E2470923A009A0597 /* Localizable.strings */; };
|
||||
C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47331A1247093B7009A0597 /* StatusMenu.swift */; };
|
||||
@ -337,6 +339,7 @@
|
||||
C464ADAB275A7A3F003FCD53 /* DomainListWC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListWC.swift; sourceTree = "<group>"; };
|
||||
C464ADAE275A7A69003FCD53 /* DomainListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListVC.swift; sourceTree = "<group>"; };
|
||||
C464ADB1275A87CA003FCD53 /* DomainListCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListCellProtocol.swift; sourceTree = "<group>"; };
|
||||
C46E206C28299B3800D909D6 /* Updater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = "<group>"; };
|
||||
C46FA23E246C358E00944F05 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = "<group>"; };
|
||||
C473319E2470923A009A0597 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
C47331A1247093B7009A0597 /* StatusMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusMenu.swift; sourceTree = "<group>"; };
|
||||
@ -786,6 +789,7 @@
|
||||
C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */,
|
||||
C4EED88827A48778006D7272 /* InterAppHandler.swift */,
|
||||
C4D8016522B1584700C6DA1B /* Startup.swift */,
|
||||
C46E206C28299B3800D909D6 /* Updater.swift */,
|
||||
);
|
||||
path = App;
|
||||
sourceTree = "<group>";
|
||||
@ -1178,6 +1182,7 @@
|
||||
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */,
|
||||
C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */,
|
||||
C41CA5ED2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */,
|
||||
C46E206D28299B3800D909D6 /* Updater.swift in Sources */,
|
||||
C412E5FC25700D5300A1FB67 /* HomebrewPackage.swift in Sources */,
|
||||
C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */,
|
||||
C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */,
|
||||
@ -1346,6 +1351,7 @@
|
||||
C418898A275FE8CB001EF227 /* Filesystem.swift in Sources */,
|
||||
C4F780C625D80B75000DBC97 /* XibLoadable.swift in Sources */,
|
||||
C4EE55AA27708B9E001DF387 /* PMHeaderView.swift in Sources */,
|
||||
C46E206E28299B3800D909D6 /* Updater.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -65,6 +65,10 @@ struct Constants {
|
||||
string: "https://github.com/nicoverbruggen/phpmon#%EF%B8%8F-faq--troubleshooting"
|
||||
)!
|
||||
|
||||
static let GitHubReleases = URL(
|
||||
string: "https://github.com/nicoverbruggen/phpmon/releases"
|
||||
)!
|
||||
|
||||
static let StableBuildCaskFile = URL(
|
||||
string: "https://raw.githubusercontent.com/nicoverbruggen/homebrew-cask/master/Casks/phpmon.rb"
|
||||
)!
|
||||
|
120
phpmon/Domain/App/Updater.swift
Normal file
120
phpmon/Domain/App/Updater.swift
Normal file
@ -0,0 +1,120 @@
|
||||
//
|
||||
// Updater.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 09/05/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AppKit
|
||||
|
||||
class Updater {
|
||||
|
||||
public static var enabled: Bool = {
|
||||
return Preferences.isEnabled(.automaticBackgroundUpdateCheck)
|
||||
}()
|
||||
|
||||
public static func checkForUpdates(background: Bool = true) {
|
||||
// Information about the status of a potential background update
|
||||
if background {
|
||||
if !Preferences.isEnabled(.automaticBackgroundUpdateCheck) {
|
||||
Log.info("Automatic updates are disabled. No check will be performed.")
|
||||
return
|
||||
} else {
|
||||
Log.info("Automatic updates are enabled, a check will be performed.")
|
||||
}
|
||||
}
|
||||
|
||||
// Actually check for updates
|
||||
let caskFile = App.version.contains("-dev")
|
||||
? Constants.Urls.DevBuildCaskFile.absoluteString
|
||||
: Constants.Urls.StableBuildCaskFile.absoluteString
|
||||
|
||||
// We'll find out what the new version is by using `curl`
|
||||
var command = "curl -s"
|
||||
|
||||
if background {
|
||||
// If running as a background check, should only waste at most 2 secs of time
|
||||
command = "curl -s --max-time 2"
|
||||
}
|
||||
|
||||
let versionString = Shell.pipe(
|
||||
"\(command) '\(caskFile)' | grep version"
|
||||
)
|
||||
|
||||
guard let onlineVersion = VersionExtractor.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 !background {
|
||||
notifyAboutConnectionIssue()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
guard let current = VersionExtractor.from(App.shortVersion) else {
|
||||
Log.err("We couldn't parse the current version number!")
|
||||
return
|
||||
}
|
||||
|
||||
switch onlineVersion.versionCompare(current) {
|
||||
case .orderedAscending:
|
||||
Log.info("You are running a newer version of PHP Monitor.")
|
||||
case .orderedDescending:
|
||||
Log.info("There is a newer version (\(onlineVersion)) available!")
|
||||
notifyAboutNewerVersion(version: onlineVersion)
|
||||
case .orderedSame:
|
||||
Log.info("The installed version \(current) matches the latest release (\(onlineVersion)).")
|
||||
}
|
||||
}
|
||||
|
||||
private static func notifyAboutNewerVersion(version: String) {
|
||||
let dev = App.version.contains("-dev") ? "-dev" : ""
|
||||
|
||||
DispatchQueue.main.async {
|
||||
BetterAlert().withInformation(
|
||||
title: "updater.alerts.newer_version_available.title".localized(version),
|
||||
subtitle: "updater.alerts.newer_version_available.subtitle".localized,
|
||||
description: HomebrewDiagnostics.customCaskInstalled
|
||||
? "updater.installation_source.brew".localized
|
||||
: "updater.installation_source.direct".localized
|
||||
)
|
||||
.withPrimary(
|
||||
text: "updater.alerts.buttons.release_notes".localized,
|
||||
action: { vc in
|
||||
vc.close(with: .OK)
|
||||
NSWorkspace.shared.open(
|
||||
Constants.Urls.GitHubReleases.appendingPathComponent("/tag/v\(version)\(dev)")
|
||||
)
|
||||
}
|
||||
)
|
||||
.withTertiary(text: "Close", action: { vc in
|
||||
vc.close(with: .OK)
|
||||
})
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private static func notifyAboutConnectionIssue() {
|
||||
DispatchQueue.main.async {
|
||||
BetterAlert().withInformation(
|
||||
title: "updater.errors.cannot_check_for_update.title".localized,
|
||||
subtitle: "updater.errors.cannot_check_for_update.subtitle".localized,
|
||||
description: "updater.errors.cannot_check_for_update.description".localized(
|
||||
App.version
|
||||
)
|
||||
)
|
||||
.withTertiary(
|
||||
text: "updater.errors.buttons.releases_on_github".localized,
|
||||
action: { _ in
|
||||
NSWorkspace.shared.open(Constants.Urls.GitHubReleases)
|
||||
}
|
||||
)
|
||||
.withPrimary(text: "OK")
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -10,6 +10,25 @@ import Foundation
|
||||
|
||||
class HomebrewDiagnostics {
|
||||
|
||||
/**
|
||||
Determines the Homebrew taps the user has installed.
|
||||
*/
|
||||
public static var installedTaps: [String] = {
|
||||
return Shell
|
||||
.pipe("\(Paths.brew) tap")
|
||||
.split(separator: "\n")
|
||||
.map { string in
|
||||
return String(string)
|
||||
}
|
||||
}()
|
||||
|
||||
/**
|
||||
Determines whether the PHP Monitor Cask is installed.
|
||||
*/
|
||||
public static var customCaskInstalled: Bool = {
|
||||
return installedTaps.contains("nicoverbruggen/cask")
|
||||
}()
|
||||
|
||||
/**
|
||||
It is possible to have the `shivammathur/php` tap installed, and for the core homebrew information to be outdated.
|
||||
This will then result in two different aliases claiming to point to the same formula (`php`).
|
||||
@ -55,6 +74,10 @@ class HomebrewDiagnostics {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This method, unsurprisingly, is supposed to show a specific alert about this alias conflict
|
||||
with the `shivammathur/php` tap.
|
||||
*/
|
||||
public static func presentAlertAboutConflict() {
|
||||
DispatchQueue.main.async {
|
||||
BetterAlert()
|
||||
|
@ -29,6 +29,12 @@ extension MainMenu {
|
||||
When the environment is all clear and the app can run, let's go.
|
||||
*/
|
||||
private func onEnvironmentPass() {
|
||||
// Determine install method
|
||||
Log.info(HomebrewDiagnostics.customCaskInstalled
|
||||
? "The app has probably been installed via Homebrew Cask."
|
||||
: "The app has probably been installed directly."
|
||||
)
|
||||
|
||||
// Attempt to find out more info about Valet
|
||||
if Valet.shared.version != nil {
|
||||
Log.info("PHP Monitor has extracted the version number of Valet: \(Valet.shared.version!)")
|
||||
@ -86,8 +92,6 @@ extension MainMenu {
|
||||
|
||||
NotificationCenter.default.post(name: Events.ServicesUpdated, object: nil)
|
||||
|
||||
Log.info("PHP Monitor is ready to serve!")
|
||||
|
||||
// Schedule a request to fetch the PHP version every 60 seconds
|
||||
DispatchQueue.main.async { [self] in
|
||||
App.shared.timer = Timer.scheduledTimer(
|
||||
@ -100,7 +104,12 @@ extension MainMenu {
|
||||
}
|
||||
|
||||
Stats.incrementSuccessfulLaunchCount()
|
||||
|
||||
Stats.evaluateSponsorMessageShouldBeDisplayed()
|
||||
|
||||
Updater.checkForUpdates()
|
||||
|
||||
Log.info("PHP Monitor is ready to serve!")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,32 +339,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
||||
|
||||
@objc func checkForUpdates() {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
let caskFile = App.version.contains("-dev")
|
||||
? Constants.Urls.DevBuildCaskFile.absoluteString
|
||||
: Constants.Urls.StableBuildCaskFile.absoluteString
|
||||
|
||||
let versionString = Shell.pipe(
|
||||
"curl -s '\(caskFile)' | grep version"
|
||||
)
|
||||
|
||||
guard let onlineVersion = VersionExtractor.from(versionString) else {
|
||||
Log.err("We couldn't check for updates!")
|
||||
return
|
||||
}
|
||||
|
||||
guard let current = VersionExtractor.from(App.shortVersion) else {
|
||||
Log.err("We couldn't parse the current version number!")
|
||||
return
|
||||
}
|
||||
|
||||
switch onlineVersion.versionCompare(current) {
|
||||
case .orderedAscending:
|
||||
Log.info("You are running a newer version of PHP Monitor.")
|
||||
case .orderedDescending:
|
||||
Log.info("There is a newer version (\(onlineVersion)) available!")
|
||||
case .orderedSame:
|
||||
Log.info("The installed version matches the latest release (\(current)).")
|
||||
}
|
||||
Updater.checkForUpdates(background: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ enum PreferenceName: String {
|
||||
case autoComposerGlobalUpdateAfterSwitch = "auto_composer_global_update_after_switch"
|
||||
case allowProtocolForIntegrations = "allow_protocol_for_integrations"
|
||||
case globalHotkey = "global_hotkey"
|
||||
case automaticBackgroundUpdateCheck = "backgroundUpdateCheck"
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,6 +77,7 @@ class Preferences {
|
||||
PreferenceName.autoServiceRestartAfterExtensionToggle.rawValue: true,
|
||||
PreferenceName.autoComposerGlobalUpdateAfterSwitch.rawValue: false,
|
||||
PreferenceName.allowProtocolForIntegrations.rawValue: true,
|
||||
PreferenceName.automaticBackgroundUpdateCheck.rawValue: true,
|
||||
/// Stats
|
||||
InternalStats.switchCount.rawValue: 0,
|
||||
InternalStats.launchCount.rawValue: 0,
|
||||
@ -145,6 +147,8 @@ class Preferences {
|
||||
forKey: PreferenceName.autoComposerGlobalUpdateAfterSwitch.rawValue) as Any,
|
||||
.allowProtocolForIntegrations: UserDefaults.standard.bool(
|
||||
forKey: PreferenceName.allowProtocolForIntegrations.rawValue) as Any,
|
||||
.automaticBackgroundUpdateCheck: UserDefaults.standard.bool(
|
||||
forKey: PreferenceName.automaticBackgroundUpdateCheck.rawValue) as Any,
|
||||
|
||||
// Part 2: Always Strings
|
||||
.globalHotkey: UserDefaults.standard.string(
|
||||
|
@ -53,7 +53,8 @@ class PrefsVC: NSViewController {
|
||||
getAutoRestartPreferenceView(),
|
||||
getAutomaticComposerUpdatePreferenceView(),
|
||||
getShortcutPreferenceView(),
|
||||
getIntegrationsPreferenceView()
|
||||
getIntegrationsPreferenceView(),
|
||||
getAutomaticUpdateCheckPreferenceView()
|
||||
].forEach({ self.stackView.addArrangedSubview($0) })
|
||||
}
|
||||
|
||||
@ -133,6 +134,16 @@ class PrefsVC: NSViewController {
|
||||
)
|
||||
}
|
||||
|
||||
private func getAutomaticUpdateCheckPreferenceView() -> NSView {
|
||||
return CheckboxPreferenceView.make(
|
||||
sectionText: "prefs.updates".localized,
|
||||
descriptionText: "prefs.automatic_update_check_desc".localized,
|
||||
checkboxText: "prefs.automatic_update_check_title".localized,
|
||||
preference: .automaticBackgroundUpdateCheck,
|
||||
action: {}
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Listening for hotkey delegate
|
||||
|
||||
var listeningForHotkeyView: HotkeyPreferenceView?
|
||||
|
@ -184,6 +184,7 @@
|
||||
"prefs.services" = "Services:";
|
||||
"prefs.switcher" = "Switcher:";
|
||||
"prefs.integrations" = "Integrations:";
|
||||
"prefs.updates" = "Updates:";
|
||||
|
||||
"prefs.icon_options.php" = "Display PHP Icon";
|
||||
"prefs.icon_options.elephant" = "Display Elephant Icon";
|
||||
@ -205,6 +206,9 @@
|
||||
|
||||
"prefs.open_protocol_title" = "Allow third-party integrations";
|
||||
"prefs.open_protocol_desc" = "When checked, this will allow the interaction with third party utilities to work (e.g. Alfred, Raycast). If you disable this, PHP Monitor will still receive the commands, but will not act upon them.";
|
||||
|
||||
"prefs.automatic_update_check_title" = "Automatically check for updates";
|
||||
"prefs.automatic_update_check_desc" = "When checked, PHP Monitor will automatically check if there is a newer version available, and notify you if that is the case.";
|
||||
|
||||
"prefs.shortcut_set" = "Set global shortcut";
|
||||
"prefs.shortcut_listening" = "<listening for keypress>";
|
||||
@ -373,6 +377,20 @@ You can do this by running `composer global update` in your terminal. After that
|
||||
"alert.errors.homebrew_permissions.applescript_returned_nil.title" = "Restore Homebrew Permissions has been cancelled.";
|
||||
"alert.errors.homebrew_permissions.applescript_returned_nil.description" = "The outcome of the script that is executed to adjust the permissions returned nil, which usually means that you did not grant administrative permissions to PHP Monitor.\n\nIf you clicked on Cancel during the authentication prompt, this is normal. If you did actually authenticate and you are still seeing this message, something probably went wrong.";
|
||||
|
||||
// CHECK FOR UPDATES
|
||||
|
||||
"updater.alerts.newer_version_available.title" = "A newer version of 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. Sometimes, there's even cool new features!";
|
||||
"updater.alerts.newer_version_available.description" = "PHP Monitor is supposed to be updated via Homebrew, so there is no built-in updater. This check is only meant to inform you of the existence of a new version, you do not need to upgrade.";
|
||||
"updater.installation_source.brew" = "You appear to have installed PHP Monitor via Homebrew (or have at least tapped the required Caskfile) so it is recommended that you upgrade via the terminal by running `brew upgrade phpmon`.";
|
||||
"updater.installation_source.direct" = "You do not appear to have installed PHP Monitor via Homebrew, so you will need to visit GitHub to download the latest update.";
|
||||
"updater.alerts.buttons.release_notes" = "View Release Notes";
|
||||
|
||||
"updater.alerts.cannot_check_for_update.title" = "PHP Monitor could not determine if a newer version is available.";
|
||||
"updater.alerts.cannot_check_for_update.subtitle" = "You might not be connected to the internet, are blocking traffic or GitHub is down and won't allow you to check for updates. If you keep seeing this message, you may want to manually check the releases page.";
|
||||
"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";
|
||||
|
||||
// WARNINGS ABOUT NON-DEFAULT TLD
|
||||
|
||||
"alert.warnings.tld_issue.title" = "You are not using `.test` as the TLD for Valet.";
|
||||
|
Reference in New Issue
Block a user