From a6387e96e78fe75121fdb3bb02bfaf207e4b8439 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Tue, 21 Dec 2021 15:30:50 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Separate=20some=20of=20the?= =?UTF-8?q?=20PHP=20config=20logic=20from=20the=20app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 22 ++++++- phpmon-cli/main.swift | 5 ++ phpmon-common/Command.swift | 2 +- phpmon-common/Paths.swift | 37 +++++------- phpmon-common/PhpSwitcher.swift | 60 +++++++++++++++++++ phpmon-common/Shell.swift | 30 +++++----- phpmon-tests/{ => Test Files}/brew.json | 0 phpmon-tests/{ => Test Files}/php.ini | 0 .../{ => Test Files}/valet-config.json | 0 phpmon/Domain/Core/Actions.swift | 18 +++--- phpmon/Domain/Core/App.swift | 58 ++++++------------ phpmon/Domain/Core/AppDelegate.swift | 11 ++++ phpmon/Domain/Core/Startup.swift | 4 +- .../Homebrew/HomebrewDiagnostics.swift | 6 +- phpmon/Domain/Menu/MainMenu.swift | 38 +++++++----- phpmon/Domain/Menu/StatusMenu.swift | 42 +++++-------- phpmon/Domain/PHP/ActivePhpInstallation.swift | 2 +- phpmon/Domain/Watcher/App+ConfigWatch.swift | 29 ++++----- 18 files changed, 211 insertions(+), 153 deletions(-) create mode 100644 phpmon-common/PhpSwitcher.swift rename phpmon-tests/{ => Test Files}/brew.json (100%) rename phpmon-tests/{ => Test Files}/php.ini (100%) rename phpmon-tests/{ => Test Files}/valet-config.json (100%) diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index fc53ebe..89d4e01 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -24,6 +24,9 @@ 54FCFD31276C8DA4004CE748 /* HotkeyPreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54FCFD2F276C8DA4004CE748 /* HotkeyPreferenceView.swift */; }; C405A4D024B9B9140062FAFA /* InternetAccessPolicy.strings in Resources */ = {isa = PBXBuildFile; fileRef = C405A4CE24B9B9130062FAFA /* InternetAccessPolicy.strings */; }; C405A4D124B9B9140062FAFA /* InternetAccessPolicy.plist in Resources */ = {isa = PBXBuildFile; fileRef = C405A4CF24B9B9140062FAFA /* InternetAccessPolicy.plist */; }; + C40C7F1E2772136000DDDCDC /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F1D2772136000DDDCDC /* PhpSwitcher.swift */; }; + C40C7F1F2772136000DDDCDC /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F1D2772136000DDDCDC /* PhpSwitcher.swift */; }; + C40C7F202772136000DDDCDC /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F1D2772136000DDDCDC /* PhpSwitcher.swift */; }; C412E5FC25700D5300A1FB67 /* HomebrewPackage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C412E5FB25700D5300A1FB67 /* HomebrewPackage.swift */; }; C415D3B72770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; }; C415D3B82770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; }; @@ -176,6 +179,7 @@ 54FCFD2F276C8DA4004CE748 /* HotkeyPreferenceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HotkeyPreferenceView.swift; sourceTree = ""; }; C405A4CE24B9B9130062FAFA /* InternetAccessPolicy.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = InternetAccessPolicy.strings; sourceTree = ""; }; C405A4CF24B9B9140062FAFA /* InternetAccessPolicy.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = InternetAccessPolicy.plist; sourceTree = ""; }; + C40C7F1D2772136000DDDCDC /* PhpSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpSwitcher.swift; sourceTree = ""; }; C412E5FB25700D5300A1FB67 /* HomebrewPackage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewPackage.swift; sourceTree = ""; }; C415D3B62770F294005EF286 /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = ""; }; C415D3D62770F341005EF286 /* phpmon-cli */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "phpmon-cli"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -321,6 +325,16 @@ path = IAP; sourceTree = ""; }; + C40C7F1C27720E1400DDDCDC /* Test Files */ = { + isa = PBXGroup; + children = ( + C4AF9F70275445FF00D44ED0 /* valet-config.json */, + C43A8A1F25D9D1D700591B77 /* brew.json */, + C4F780A725D80AE8000DBC97 /* php.ini */, + ); + path = "Test Files"; + sourceTree = ""; + }; C415D3D72770F341005EF286 /* phpmon-cli */ = { isa = PBXGroup; children = ( @@ -494,6 +508,7 @@ C4B5853D2770FE3900DA4FBE /* Command.swift */, C4B5853B2770FE3900DA4FBE /* Paths.swift */, C4B5853C2770FE3900DA4FBE /* Shell.swift */, + C40C7F1D2772136000DDDCDC /* PhpSwitcher.swift */, ); path = "phpmon-common"; sourceTree = ""; @@ -527,10 +542,8 @@ C4F7807A25D7F84B000DBC97 /* phpmon-tests */ = { isa = PBXGroup; children = ( - C4AF9F70275445FF00D44ED0 /* valet-config.json */, - C43A8A1F25D9D1D700591B77 /* brew.json */, - C4F780A725D80AE8000DBC97 /* php.ini */, C4F7807D25D7F84B000DBC97 /* Info.plist */, + C40C7F1C27720E1400DDDCDC /* Test Files */, C4F7809B25D80344000DBC97 /* CommandTest.swift */, C4F780AD25D80B37000DBC97 /* ExtensionParserTest.swift */, C43A8A2325D9D20D00591B77 /* BrewJsonParserTest.swift */, @@ -702,6 +715,7 @@ C4B585432770FE3900DA4FBE /* Shell.swift in Sources */, C4B585462770FE3900DA4FBE /* Command.swift in Sources */, C415D3E12770F34D005EF286 /* AllowedArguments.swift in Sources */, + C40C7F202772136000DDDCDC /* PhpSwitcher.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -750,6 +764,7 @@ C41C1B4B22B019FF00E7CF16 /* ActivePhpInstallation.swift in Sources */, C4188989275FE8CB001EF227 /* Filesystem.swift in Sources */, C4B97B7B275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */, + C40C7F1E2772136000DDDCDC /* PhpSwitcher.swift in Sources */, C476FF9822B0DD830098105B /* Alert.swift in Sources */, C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */, C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */, @@ -820,6 +835,7 @@ C481F79A26164A7C004FBCFF /* Preferences.swift in Sources */, C4B585422770FE3900DA4FBE /* Shell.swift in Sources */, C464ADAD275A7A3F003FCD53 /* SiteListWC.swift in Sources */, + C40C7F1F2772136000DDDCDC /* PhpSwitcher.swift in Sources */, C4F780CB25D80B75000DBC97 /* StatsView.swift in Sources */, C464ADB0275A7A6A003FCD53 /* SiteListVC.swift in Sources */, C43A8A1A25D9CD1000591B77 /* Utility.swift in Sources */, diff --git a/phpmon-cli/main.swift b/phpmon-cli/main.swift index 5070216..64ece82 100644 --- a/phpmon-cli/main.swift +++ b/phpmon-cli/main.swift @@ -10,6 +10,11 @@ import Foundation // First, let's read the initial command line argument +// REFACTOR REQUIRED +// Information about the Homebrew linked alias +// Information about the PHP versions +// etc.: needs to be stored in a separate object we can instantiate here and in PHP Monitor. + print(CommandLine.arguments) if CommandLine.arguments.count != 3 { diff --git a/phpmon-common/Command.swift b/phpmon-common/Command.swift index 7fc07e4..941172a 100644 --- a/phpmon-common/Command.swift +++ b/phpmon-common/Command.swift @@ -1,6 +1,6 @@ // // Command.swift -// PMCommon +// phpmon-common // // Copyright © 2021 Nico Verbruggen. All rights reserved. // diff --git a/phpmon-common/Paths.swift b/phpmon-common/Paths.swift index 9d766ce..5231893 100644 --- a/phpmon-common/Paths.swift +++ b/phpmon-common/Paths.swift @@ -1,38 +1,24 @@ // // Paths.swift -// PMCommon +// phpmon-common // // Copyright © 2021 Nico Verbruggen. All rights reserved. // import Foundation -public enum HomebrewDir: String { - case opt = "/opt/homebrew" - case usr = "/usr/local" -} - +/** + The `Paths` class is used to locate various binaries on the system, + and provides a full + */ public class Paths { public static let shared = Paths() - var baseDir : HomebrewDir + + private var baseDir : Paths.HomebrewDir init() { - let optBrewFound = Shell.fileExists("\(HomebrewDir.opt.rawValue)/bin/brew") - let usrBrewFound = Shell.fileExists("\(HomebrewDir.usr.rawValue)/bin/brew") - - if (optBrewFound) { - // This is usually the case with Homebrew installed on Apple Silicon - baseDir = .opt - } else if (usrBrewFound) { - // This is usually the case with Homebrew installed on Intel (or Rosetta 2) - baseDir = .usr - } else { - // Falling back to default "legacy" Homebrew location (for Intel) - print("Seems like we couldn't determine the Homebrew directory.") - print("This usually means we're in trouble... (no Homebrew?)") - baseDir = .usr - } + baseDir = Shell.fileExists("\(HomebrewDir.opt.rawValue)/bin/brew") ? .opt : .usr } // - MARK: Binaries @@ -71,4 +57,11 @@ public class Paths { return "\(shared.baseDir.rawValue)/etc" } + // MARK: - Enum + + public enum HomebrewDir: String { + case opt = "/opt/homebrew" + case usr = "/usr/local" + } + } diff --git a/phpmon-common/PhpSwitcher.swift b/phpmon-common/PhpSwitcher.swift new file mode 100644 index 0000000..17a824c --- /dev/null +++ b/phpmon-common/PhpSwitcher.swift @@ -0,0 +1,60 @@ +// +// PhpSwitcher.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 21/12/2021. +// Copyright © 2021 Nico Verbruggen. All rights reserved. +// + +import Foundation + +protocol PhpSwitcherDelegate: AnyObject { + func switcherDidStartSwitching() + func switcherDidCompleteSwitch() +} + +class PhpSwitcher { + + init() { + self.currentInstall = ActivePhpInstallation() + } + + /** The delegate that is informed of updates. */ + weak var delegate: PhpSwitcherDelegate? + + /** The static app instance. Accessible at any time. */ + static let shared = PhpSwitcher() + + /** Whether the switcher is busy performing any actions. */ + var isBusy: Bool = false + + /** All available versions of PHP. */ + var availablePhpVersions: [String] = [] + + /** Cached information about the PHP installations. */ + var cachedPhpInstallations: [String: PhpInstallation] = [:] + + /** Static accessor for `PhpSwitcher.shared.currentInstall`. */ + static var phpInstall: ActivePhpInstallation { + return Self.shared.currentInstall + } + + /** Information about the currently linked PHP installation. */ + var currentInstall: ActivePhpInstallation + + /** + The version that the `php` formula via Brew is aliased to on the current system. + + If you're up to date, `php` will be aliased to the latest version, + but that might not be the case. + */ + var brewPhpVersion: String { + return homebrewPackage.version + } + + /** + Information we were able to discern from the Homebrew info command. + */ + var homebrewPackage: HomebrewPackage! = nil + +} diff --git a/phpmon-common/Shell.swift b/phpmon-common/Shell.swift index 87ef921..11c6730 100644 --- a/phpmon-common/Shell.swift +++ b/phpmon-common/Shell.swift @@ -1,6 +1,6 @@ // // Shell.swift -// PMCommon +// phpmon-common // // Copyright © 2021 Nico Verbruggen. All rights reserved. // @@ -80,7 +80,7 @@ public class Shell { public func executeSynchronously( _ command: String, requiresPath: Bool = false - ) -> ShellOutput { + ) -> Shell.Output { let outputPipe = Pipe() let errorPipe = Pipe() @@ -91,7 +91,7 @@ public class Shell { task.launch() task.waitUntilExit() - return ShellOutput( + return Shell.Output( standardOutput: String( data: outputPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8 @@ -162,18 +162,18 @@ public class Shell { NotificationCenter.default.removeObserver(pipe.fileHandleForReading) } } -} - -public class ShellOutput { - public let standardOutput: String - public let errorOutput: String - public let task: Process - init(standardOutput: String, - errorOutput: String, - task: Process) { - self.standardOutput = standardOutput - self.errorOutput = errorOutput - self.task = task + public class Output { + public let standardOutput: String + public let errorOutput: String + public let task: Process + + init(standardOutput: String, + errorOutput: String, + task: Process) { + self.standardOutput = standardOutput + self.errorOutput = errorOutput + self.task = task + } } } diff --git a/phpmon-tests/brew.json b/phpmon-tests/Test Files/brew.json similarity index 100% rename from phpmon-tests/brew.json rename to phpmon-tests/Test Files/brew.json diff --git a/phpmon-tests/php.ini b/phpmon-tests/Test Files/php.ini similarity index 100% rename from phpmon-tests/php.ini rename to phpmon-tests/Test Files/php.ini diff --git a/phpmon-tests/valet-config.json b/phpmon-tests/Test Files/valet-config.json similarity index 100% rename from phpmon-tests/valet-config.json rename to phpmon-tests/Test Files/valet-config.json diff --git a/phpmon/Domain/Core/Actions.swift b/phpmon/Domain/Core/Actions.swift index 5bbc098..19773f6 100644 --- a/phpmon/Domain/Core/Actions.swift +++ b/phpmon/Domain/Core/Actions.swift @@ -20,7 +20,7 @@ class Actions { // Make sure the aliased version is detected // The user may have `php` installed, but not e.g. `php@8.0` // We should also detect that as a version that is installed - let phpAlias = App.shared.brewPhpVersion + let phpAlias = PhpSwitcher.shared.brewPhpVersion // Avoid inserting a duplicate if (!versionsOnly.contains(phpAlias) && Shell.fileExists("\(Paths.optPath)/php/bin/php")) { @@ -29,7 +29,7 @@ class Actions { print("The PHP versions that were detected are: \(versionsOnly)") - App.shared.availablePhpVersions = versionsOnly + PhpSwitcher.shared.availablePhpVersions = versionsOnly Actions.extractPhpLongVersions() return versionsOnly @@ -42,11 +42,11 @@ class Actions { public static func extractPhpLongVersions() { var mappedVersions: [String: PhpInstallation] = [:] - App.shared.availablePhpVersions.forEach { version in + PhpSwitcher.shared.availablePhpVersions.forEach { version in mappedVersions[version] = PhpInstallation(version) } - App.shared.cachedPhpInstallations = mappedVersions + PhpSwitcher.shared.cachedPhpInstallations = mappedVersions } /** @@ -82,7 +82,7 @@ class Actions { public static func restartPhpFpm() { - brew("services restart \(App.phpInstall!.formula)", sudo: true) + brew("services restart \(PhpSwitcher.phpInstall.formula)", sudo: true) } public static func restartNginx() @@ -97,7 +97,7 @@ class Actions { public static func stopAllServices() { - brew("services stop \(App.phpInstall!.formula)", sudo: true) + brew("services stop \(PhpSwitcher.phpInstall.formula)", sudo: true) brew("services stop nginx", sudo: true) brew("services stop dnsmasq", sudo: true) } @@ -137,7 +137,7 @@ class Actions { group.enter() DispatchQueue.global(qos: .userInitiated).async { - let formula = (available == App.shared.brewPhpVersion) + let formula = (available == PhpSwitcher.shared.brewPhpVersion) ? "php" : "php@\(available)" brew("unlink \(formula)") @@ -151,7 +151,7 @@ class Actions { print("All versions have been unlinked!") print("Linking the new version!") - let formula = (version == App.shared.brewPhpVersion) ? "php" : "php@\(version)" + let formula = (version == PhpSwitcher.shared.brewPhpVersion) ? "php" : "php@\(version)" brew("link \(formula) --overwrite --force") brew("services start \(formula)", sudo: true) @@ -205,7 +205,7 @@ class Actions { brew("services restart dnsmasq", sudo: true) detectPhpVersions().forEach { (version) in - let formula = (version == App.shared.brewPhpVersion) ? "php" : "php@\(version)" + let formula = (version == PhpSwitcher.shared.brewPhpVersion) ? "php" : "php@\(version)" brew("unlink php@\(version)") brew("services stop \(formula)") brew("services stop \(formula)", sudo: true) diff --git a/phpmon/Domain/Core/App.swift b/phpmon/Domain/Core/App.swift index 9b77ed1..2a578d1 100644 --- a/phpmon/Domain/Core/App.swift +++ b/phpmon/Domain/Core/App.swift @@ -8,13 +8,17 @@ import Cocoa import HotKey -class App { +class App: PhpSwitcherDelegate { // MARK: Static Vars /** The static app instance. Accessible at any time. */ static let shared = App() + init() { + PhpSwitcher.shared.delegate = self + } + /** Retrieve the version number from the main info dictionary, Info.plist. */ static var version: String { let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String @@ -22,14 +26,9 @@ class App { return "\(version) (\(build))" } - /** Information about the currently linked PHP installation. */ - static var phpInstall: ActivePhpInstallation? { - return App.shared.currentInstall - } - /** Whether the app is busy doing something. Used to determine what UI to display. */ static var busy: Bool { - return App.shared.busy + return PhpSwitcher.shared.isBusy } // MARK: Variables @@ -43,46 +42,13 @@ class App { /** The window controller of the currently active site list window. */ var siteListWindowController: SiteListWC? = nil - /** Whether the application is busy switching versions. */ - var busy: Bool = false - - /** The currently active installation of PHP. */ - var currentInstall: ActivePhpInstallation? = nil { - didSet { - handlePhpConfigWatcher() - } - } - - /** All available versions of PHP. */ - var availablePhpVersions: [String] = [] - - /** Cached information about the PHP installations. */ - var cachedPhpInstallations: [String: PhpInstallation] = [:] - /** List of detected (installed) applications that PHP Monitor can work with. */ var detectedApplications: [Application] = [] /** Timer that will periodically reload info about the user's PHP installation. */ var timer: Timer? - /** Information we were able to discern from the Homebrew info command (as JSON). */ - var brewPhpPackage: HomebrewPackage! = nil { - didSet { - brewPhpVersion = brewPhpPackage!.version - } - } - - /** - The version that the `php` formula via Brew is aliased to on the current system. - - If you're up to date, `php` will be aliased to the latest version, - but that might not be the case. - - We'll technically default to the version in Constants.swift, but the information - should always be loaded from Homebrew itself upon startup. - */ - var brewPhpVersion: String = Constants.LatestStablePhpVersion - + // MARK: - Global Hotkey /** @@ -112,4 +78,14 @@ class App { The `PhpConfigWatcher` is responsible for watching the `.ini` files and the `.conf.d` folder. */ var watcher: PhpConfigWatcher! + + // MARK: - PhpSwitcherDelegate + + func switcherDidStartSwitching() { + } + + func switcherDidCompleteSwitch() { + PhpSwitcher.shared.currentInstall = ActivePhpInstallation() + handlePhpConfigWatcher() + } } diff --git a/phpmon/Domain/Core/AppDelegate.swift b/phpmon/Domain/Core/AppDelegate.swift index a963b6e..ecd5420 100644 --- a/phpmon/Domain/Core/AppDelegate.swift +++ b/phpmon/Domain/Core/AppDelegate.swift @@ -20,6 +20,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele */ let sharedShell: Shell + /** + The PhpSwitcher singleton that handles PHP version + detection, as well as switching. + + - Note: It is important to initialize the switcher + before the `App` singleton, so that the delegate + is set correctly. + */ + let switcher: PhpSwitcher + /** The App singleton contains information about the state of the application and global variables. @@ -55,6 +65,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele print("Version \(App.version)") print("==================================") self.sharedShell = Shell.user + self.switcher = PhpSwitcher.shared self.state = App.shared self.menu = MainMenu.shared self.paths = Paths.shared diff --git a/phpmon/Domain/Core/Startup.swift b/phpmon/Domain/Core/Startup.swift index b42c8ab..747a0d2 100644 --- a/phpmon/Domain/Core/Startup.swift +++ b/phpmon/Domain/Core/Startup.swift @@ -91,12 +91,12 @@ class Startup { let brewPhpAlias = Shell.pipe("\(Paths.brew) info php --json"); - App.shared.brewPhpPackage = try! JSONDecoder().decode( + PhpSwitcher.shared.homebrewPackage = try! JSONDecoder().decode( [HomebrewPackage].self, from: brewPhpAlias.data(using: .utf8)! ).first! - print("When on your system, the `php` formula means version \(App.shared.brewPhpVersion)!") + print("When on your system, the `php` formula means version \(PhpSwitcher.shared.brewPhpVersion)!") } /** diff --git a/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift b/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift index fd327a8..a41695c 100644 --- a/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift +++ b/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift @@ -46,12 +46,12 @@ class HomebrewDiagnostics { from: tapAlias.data(using: .utf8)! ).first! - if tapPhp.version != App.shared.brewPhpVersion { + if tapPhp.version != PhpSwitcher.shared.brewPhpVersion { print("The `php` formula alias seems to be the different between the tap and core. This could be a problem!") print("Determining whether both of these versions are installed...") - let bothInstalled = App.shared.availablePhpVersions.contains(tapPhp.version) - && App.shared.availablePhpVersions.contains(App.shared.brewPhpVersion) + let bothInstalled = PhpSwitcher.shared.availablePhpVersions.contains(tapPhp.version) + && PhpSwitcher.shared.availablePhpVersions.contains(PhpSwitcher.shared.brewPhpVersion) if bothInstalled { print("Both conflicting aliases seem to be installed, warning the user!") diff --git a/phpmon/Domain/Menu/MainMenu.swift b/phpmon/Domain/Menu/MainMenu.swift index 9f5486a..899bb94 100644 --- a/phpmon/Domain/Menu/MainMenu.swift +++ b/phpmon/Domain/Menu/MainMenu.swift @@ -57,9 +57,13 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { print("Determining broken PHP-FPM...") // Attempt to find out if PHP-FPM is broken - let installation = App.phpInstall! + let installation = PhpSwitcher.phpInstall installation.notifyAboutBrokenPhpFpm() + // Set up the config watchers on launch (these are automatically updated via delegate methods if the user switches) + print("Setting up watchers...") + App.shared.handlePhpConfigWatcher() + print("Detecting applications...") // Attempt to load list of applications App.shared.detectedApplications = Application.detectPresetApplications() @@ -82,7 +86,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { App.shared.timer = Timer.scheduledTimer( timeInterval: 60, target: self, - selector: #selector(updatePhpVersionInStatusBar), + selector: #selector(refreshActiveInstallation), userInfo: nil, repeats: true ) @@ -181,12 +185,12 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { */ private func waitAndExecute(_ execute: @escaping () -> Void, completion: @escaping () -> Void = {}) { - App.shared.busy = true + PhpSwitcher.shared.isBusy = true setBusyImage() DispatchQueue.global(qos: .userInitiated).async { [unowned self] in update() execute() - App.shared.busy = false + PhpSwitcher.shared.isBusy = false DispatchQueue.main.async { [self] in updatePhpVersionInStatusBar() @@ -198,8 +202,12 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { // MARK: - User Interface + @objc func refreshActiveInstallation() { + PhpSwitcher.shared.currentInstall = ActivePhpInstallation() + updatePhpVersionInStatusBar() + } + @objc func updatePhpVersionInStatusBar() { - App.shared.currentInstall = ActivePhpInstallation() refreshIcon() update() } @@ -215,7 +223,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { } else { // The dynamic icon has been requested let long = Preferences.preferences[.fullPhpVersionDynamicIcon] as! Bool - setStatusBarImage(version: long ? App.phpInstall!.version.long : App.phpInstall!.version.short) + setStatusBarImage(version: long ? PhpSwitcher.phpInstall.version.long : PhpSwitcher.phpInstall.version.short) } } } @@ -335,12 +343,12 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { } func updateGlobalDependencies(notify: Bool, completion: @escaping (Bool) -> Void) { - App.shared.busy = true + PhpSwitcher.shared.isBusy = true setBusyImage() self.update() let noLongerBusy = { - App.shared.busy = false + PhpSwitcher.shared.isBusy = false DispatchQueue.main.async { [self] in self.updatePhpVersionInStatusBar() self.update() @@ -411,14 +419,14 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { } @objc func openActiveConfigFolder() { - if (App.phpInstall!.version.error) { + if (PhpSwitcher.phpInstall.version.error) { // php version was not identified Actions.openGenericPhpConfigFolder() return } // php version was identified - Actions.openPhpConfigFolder(version: App.phpInstall!.version.short) + Actions.openPhpConfigFolder(version: PhpSwitcher.phpInstall.version.short) } @objc func openGlobalComposerFolder() { @@ -431,7 +439,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { @objc func switchToPhpVersion(sender: PhpMenuItem) { setBusyImage() - App.shared.busy = true + PhpSwitcher.shared.isBusy = true DispatchQueue.global(qos: .userInitiated).async { [unowned self] in // Update the PHP version in the status bar @@ -441,8 +449,10 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { update() let completion = { + PhpSwitcher.shared.delegate?.switcherDidCompleteSwitch() + // Mark as no longer busy - App.shared.busy = false + PhpSwitcher.shared.isBusy = false // Perform UI updates on main thread DispatchQueue.main.async { [self] in @@ -454,7 +464,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { title: String(format: "notification.version_changed_title".localized, sender.version), subtitle: String(format: "notification.version_changed_desc".localized, sender.version) ) - App.phpInstall?.notifyAboutBrokenPhpFpm() + PhpSwitcher.phpInstall.notifyAboutBrokenPhpFpm() } // Run composer updates @@ -482,7 +492,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { // Will cause more issues with Homebrew and is faster Actions.switchToPhpVersion( version: sender.version, - availableVersions: App.shared.availablePhpVersions, + availableVersions: PhpSwitcher.shared.availablePhpVersions, completed: completion ) /* } */ diff --git a/phpmon/Domain/Menu/StatusMenu.swift b/phpmon/Domain/Menu/StatusMenu.swift index 609f2cc..7326462 100644 --- a/phpmon/Domain/Menu/StatusMenu.swift +++ b/phpmon/Domain/Menu/StatusMenu.swift @@ -9,18 +9,14 @@ import Cocoa class StatusMenu : NSMenu { func addPhpVersionMenuItems() { - if App.shared.currentInstall == nil { - return - } - - if App.phpInstall!.version.error { + if PhpSwitcher.phpInstall.version.error { for message in ["mi_php_broken_1", "mi_php_broken_2", "mi_php_broken_3", "mi_php_broken_4"] { addItem(NSMenuItem(title: message.localized, action: nil, keyEquivalent: "")) } return } - let phpVersionText = "\("mi_php_version".localized) \(App.phpInstall!.version.long)" + let phpVersionText = "\("mi_php_version".localized) \(PhpSwitcher.phpInstall.version.long)" addItem(HeaderView.asMenuItem(text: phpVersionText)) } @@ -30,7 +26,7 @@ class StatusMenu : NSMenu { return } - if App.shared.availablePhpVersions.count == 0 { + if PhpSwitcher.shared.availablePhpVersions.count == 0 { return } @@ -44,14 +40,14 @@ class StatusMenu : NSMenu { servicesMenu.addItem(NSMenuItem(title: "mi_help".localized, action: nil, keyEquivalent: "")) - if !App.shared.availablePhpVersions.contains(App.shared.brewPhpVersion) { + if !PhpSwitcher.shared.availablePhpVersions.contains(PhpSwitcher.shared.brewPhpVersion) { servicesMenu.addItem(NSMenuItem( - title: "mi_force_load_latest_unavailable".localized(App.shared.brewPhpVersion), + title: "mi_force_load_latest_unavailable".localized(PhpSwitcher.shared.brewPhpVersion), action: nil, keyEquivalent: "f" )) } else { servicesMenu.addItem(NSMenuItem( - title: "mi_force_load_latest".localized(App.shared.brewPhpVersion), + title: "mi_force_load_latest".localized(PhpSwitcher.shared.brewPhpVersion), action: #selector(MainMenu.forceRestartLatestPhp), keyEquivalent: "f")) } @@ -75,8 +71,6 @@ class StatusMenu : NSMenu { item.target = MainMenu.shared } - - self.setSubmenu(servicesMenu, for: services) self.addItem(services) } @@ -89,10 +83,6 @@ class StatusMenu : NSMenu { } func addPhpConfigurationMenuItems() { - if App.shared.currentInstall == nil { - return - } - // Configuration self.addItem(HeaderView.asMenuItem(text: "mi_configuration".localized)) self.addItem(NSMenuItem(title: "mi_php_config".localized, action: #selector(MainMenu.openActiveConfigFolder), keyEquivalent: "c")) @@ -102,13 +92,13 @@ class StatusMenu : NSMenu { self.addItem(NSMenuItem.separator()) self.addItem(HeaderView.asMenuItem(text: "mi_composer".localized)) self.addItem(NSMenuItem(title: "mi_global_composer".localized, action: #selector(MainMenu.openGlobalComposerFolder), keyEquivalent: "g")) - self.addItem(NSMenuItem(title: "mi_update_global_composer".localized, action: App.shared.busy ? nil : #selector(MainMenu.updateComposerDependencies), keyEquivalent: "")) + self.addItem(NSMenuItem(title: "mi_update_global_composer".localized, action: PhpSwitcher.shared.isBusy ? nil : #selector(MainMenu.updateComposerDependencies), keyEquivalent: "")) - if (App.shared.busy) { + if (PhpSwitcher.shared.isBusy) { return } - let stats = App.phpInstall!.limits + let stats = PhpSwitcher.phpInstall.limits // Stats self.addItem(NSMenuItem.separator()) @@ -122,12 +112,12 @@ class StatusMenu : NSMenu { self.addItem(NSMenuItem.separator()) self.addItem(HeaderView.asMenuItem(text: "mi_detected_extensions".localized)) - if (App.phpInstall!.extensions.count == 0) { + if (PhpSwitcher.phpInstall.extensions.count == 0) { self.addItem(NSMenuItem(title: "mi_no_extensions_detected".localized, action: nil, keyEquivalent: "")) } var shortcutKey = 1 - for phpExtension in App.phpInstall!.extensions { + for phpExtension in PhpSwitcher.phpInstall.extensions { self.addExtensionItem(phpExtension, shortcutKey) shortcutKey += 1 } @@ -140,20 +130,20 @@ class StatusMenu : NSMenu { private func addSwitchToPhpMenuItems() { var shortcutKey = 1 - for index in (0..