mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-08 04:20:07 +02:00
♻️ Big Cleanup
This commit is contained in:
@ -136,6 +136,8 @@
|
|||||||
C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; };
|
C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; };
|
||||||
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CCBA6B275C567B008C7055 /* PMWindowController.swift */; };
|
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CCBA6B275C567B008C7055 /* PMWindowController.swift */; };
|
||||||
C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CCBA6B275C567B008C7055 /* PMWindowController.swift */; };
|
C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CCBA6B275C567B008C7055 /* PMWindowController.swift */; };
|
||||||
|
C4CE3BB827B31F2E0086CA49 /* MainMenu+Switcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB727B31F2E0086CA49 /* MainMenu+Switcher.swift */; };
|
||||||
|
C4CE3BBA27B31F670086CA49 /* MainMenu+Composer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* MainMenu+Composer.swift */; };
|
||||||
C4D8016622B1584700C6DA1B /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
|
C4D8016622B1584700C6DA1B /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
|
||||||
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; };
|
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; };
|
||||||
C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */; };
|
C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */; };
|
||||||
@ -283,6 +285,8 @@
|
|||||||
C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "App+ConfigWatch.swift"; sourceTree = "<group>"; };
|
C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "App+ConfigWatch.swift"; sourceTree = "<group>"; };
|
||||||
C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpConfigWatcher.swift; sourceTree = "<group>"; };
|
C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpConfigWatcher.swift; sourceTree = "<group>"; };
|
||||||
C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = "<group>"; };
|
C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = "<group>"; };
|
||||||
|
C4CE3BB727B31F2E0086CA49 /* MainMenu+Switcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Switcher.swift"; sourceTree = "<group>"; };
|
||||||
|
C4CE3BB927B31F670086CA49 /* MainMenu+Composer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Composer.swift"; sourceTree = "<group>"; };
|
||||||
C4D8016522B1584700C6DA1B /* Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Startup.swift; sourceTree = "<group>"; };
|
C4D8016522B1584700C6DA1B /* Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Startup.swift; sourceTree = "<group>"; };
|
||||||
C4D89BC52783C99400A02B68 /* ComposerJson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerJson.swift; sourceTree = "<group>"; };
|
C4D89BC52783C99400A02B68 /* ComposerJson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerJson.swift; sourceTree = "<group>"; };
|
||||||
C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpSwitcher.swift; sourceTree = "<group>"; };
|
C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpSwitcher.swift; sourceTree = "<group>"; };
|
||||||
@ -509,6 +513,8 @@
|
|||||||
C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */,
|
C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */,
|
||||||
C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */,
|
C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */,
|
||||||
C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */,
|
C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */,
|
||||||
|
C4CE3BB727B31F2E0086CA49 /* MainMenu+Switcher.swift */,
|
||||||
|
C4CE3BB927B31F670086CA49 /* MainMenu+Composer.swift */,
|
||||||
C47331A1247093B7009A0597 /* StatusMenu.swift */,
|
C47331A1247093B7009A0597 /* StatusMenu.swift */,
|
||||||
C48D0C9525CC80B100CC7490 /* HeaderView.swift */,
|
C48D0C9525CC80B100CC7490 /* HeaderView.swift */,
|
||||||
C48D0C9925CC888B00CC7490 /* HeaderView.xib */,
|
C48D0C9925CC888B00CC7490 /* HeaderView.xib */,
|
||||||
@ -847,6 +853,7 @@
|
|||||||
C4C3ED4327834C5200AB15D8 /* CustomPrefs.swift in Sources */,
|
C4C3ED4327834C5200AB15D8 /* CustomPrefs.swift in Sources */,
|
||||||
54B48B5F275F66AE006D90C5 /* Application.swift in Sources */,
|
54B48B5F275F66AE006D90C5 /* Application.swift in Sources */,
|
||||||
C4B97B78275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */,
|
C4B97B78275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */,
|
||||||
|
C4CE3BB827B31F2E0086CA49 /* MainMenu+Switcher.swift in Sources */,
|
||||||
C415937F27A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */,
|
C415937F27A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */,
|
||||||
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */,
|
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */,
|
||||||
C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */,
|
C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */,
|
||||||
@ -880,6 +887,7 @@
|
|||||||
C476FF9822B0DD830098105B /* Alert.swift in Sources */,
|
C476FF9822B0DD830098105B /* Alert.swift in Sources */,
|
||||||
C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */,
|
C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */,
|
||||||
C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */,
|
C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */,
|
||||||
|
C4CE3BBA27B31F670086CA49 /* MainMenu+Composer.swift in Sources */,
|
||||||
C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */,
|
C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */,
|
||||||
C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */,
|
C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */,
|
||||||
C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */,
|
C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */,
|
||||||
|
@ -8,11 +8,6 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol PhpSwitcherDelegate: AnyObject {
|
|
||||||
func switcherDidStartSwitching()
|
|
||||||
func switcherDidCompleteSwitch()
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhpEnv {
|
class PhpEnv {
|
||||||
|
|
||||||
// MARK: - Initializer
|
// MARK: - Initializer
|
||||||
|
@ -8,6 +8,14 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
protocol PhpSwitcherDelegate: AnyObject {
|
||||||
|
|
||||||
|
func switcherDidStartSwitching(to: String)
|
||||||
|
|
||||||
|
func switcherDidCompleteSwitch(to: String)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protocol PhpSwitcher {
|
protocol PhpSwitcher {
|
||||||
|
|
||||||
func performSwitch(to version: String, completion: @escaping () -> Void)
|
func performSwitch(to version: String, completion: @escaping () -> Void)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import HotKey
|
import HotKey
|
||||||
|
|
||||||
class App: PhpSwitcherDelegate {
|
class App {
|
||||||
|
|
||||||
// MARK: Static Vars
|
// MARK: Static Vars
|
||||||
|
|
||||||
@ -73,20 +73,4 @@ class App: PhpSwitcherDelegate {
|
|||||||
The `PhpConfigWatcher` is responsible for watching the `.ini` files and the `.conf.d` folder.
|
The `PhpConfigWatcher` is responsible for watching the `.ini` files and the `.conf.d` folder.
|
||||||
*/
|
*/
|
||||||
var watcher: PhpConfigWatcher!
|
var watcher: PhpConfigWatcher!
|
||||||
|
|
||||||
// MARK: - PhpSwitcherDelegate
|
|
||||||
|
|
||||||
func switcherDidStartSwitching() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func switcherDidCompleteSwitch() {
|
|
||||||
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
|
||||||
handlePhpConfigWatcher()
|
|
||||||
|
|
||||||
if let window = siteListWindowController {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
window.contentVC.reloadSites()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -45,12 +45,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
|||||||
let valet: Valet
|
let valet: Valet
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The PhpSwitcher singleton that handles PHP version
|
The PhpEnv singleton that handles PHP version
|
||||||
detection, as well as switching. It is initialized
|
detection, as well as switching. It is initialized
|
||||||
when the app is ready and passed all checks.
|
when the app is ready and passed all checks.
|
||||||
*/
|
*/
|
||||||
var switcher: PhpEnv! = nil
|
var phpEnvironment: PhpEnv! = nil
|
||||||
|
|
||||||
|
/**
|
||||||
|
The logger is responsible for different levels of logging.
|
||||||
|
You can tweak the verbosity in the `init` method here.
|
||||||
|
*/
|
||||||
var logger = Log.shared
|
var logger = Log.shared
|
||||||
|
|
||||||
// MARK: - Initializer
|
// MARK: - Initializer
|
||||||
@ -59,7 +63,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
|||||||
When the application initializes, create all singletons.
|
When the application initializes, create all singletons.
|
||||||
*/
|
*/
|
||||||
override init() {
|
override init() {
|
||||||
logger.verbosity = .performance
|
logger.verbosity = .info
|
||||||
Log.info("==================================")
|
Log.info("==================================")
|
||||||
Log.info("PHP MONITOR by Nico Verbruggen")
|
Log.info("PHP MONITOR by Nico Verbruggen")
|
||||||
Log.info("Version \(App.version)")
|
Log.info("Version \(App.version)")
|
||||||
@ -73,8 +77,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initializeSwitcher() {
|
func initializeSwitcher() {
|
||||||
self.switcher = PhpEnv.shared
|
self.phpEnvironment = PhpEnv.shared
|
||||||
self.switcher.delegate = self.state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
|
98
phpmon/Domain/Menu/MainMenu+Composer.swift
Normal file
98
phpmon/Domain/Menu/MainMenu+Composer.swift
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
//
|
||||||
|
// MainMenu+Composer.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 08/02/2022.
|
||||||
|
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension MainMenu {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Updates the global dependencies and runs the completion callback when done.
|
||||||
|
This method should probably be broken up into several smaller methods at some point.
|
||||||
|
*/
|
||||||
|
func updateGlobalDependencies(notify: Bool, completion: @escaping (Bool) -> Void) {
|
||||||
|
if !Shell.fileExists("/usr/local/bin/composer") {
|
||||||
|
Alert.notify(
|
||||||
|
message: "alert.composer_missing.title".localized,
|
||||||
|
info: "alert.composer_missing.info".localized
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PhpEnv.shared.isBusy = true
|
||||||
|
setBusyImage()
|
||||||
|
self.rebuild()
|
||||||
|
|
||||||
|
let noLongerBusy = {
|
||||||
|
PhpEnv.shared.isBusy = false
|
||||||
|
DispatchQueue.main.async { [self] in
|
||||||
|
self.updatePhpVersionInStatusBar()
|
||||||
|
self.rebuild()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var window: ProgressWindowController? = ProgressWindowController.display(
|
||||||
|
title: "alert.composer_progress.title".localized,
|
||||||
|
description: "alert.composer_progress.info".localized
|
||||||
|
)
|
||||||
|
window?.setType(info: true)
|
||||||
|
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async {
|
||||||
|
let task = Shell.user.createTask(
|
||||||
|
for: "/usr/local/bin/composer global update", requiresPath: true
|
||||||
|
)
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
window?.addToConsole("/usr/local/bin/composer global update\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
Shell.captureOutput(
|
||||||
|
task,
|
||||||
|
didReceiveStdOutData: { string in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
window?.addToConsole(string)
|
||||||
|
}
|
||||||
|
Log.perf("\(string.trimmingCharacters(in: .newlines))")
|
||||||
|
},
|
||||||
|
didReceiveStdErrData: { string in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
window?.addToConsole(string)
|
||||||
|
}
|
||||||
|
Log.perf("\(string.trimmingCharacters(in: .newlines))")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
task.launch()
|
||||||
|
task.waitUntilExit()
|
||||||
|
Shell.haltCapturingOutput(task)
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if task.terminationStatus <= 0 {
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||||
|
window?.close()
|
||||||
|
if (notify) {
|
||||||
|
LocalNotification.send(
|
||||||
|
title: "alert.composer_success.title".localized,
|
||||||
|
subtitle: "alert.composer_success.info".localized
|
||||||
|
)
|
||||||
|
}
|
||||||
|
window = nil
|
||||||
|
noLongerBusy()
|
||||||
|
completion(true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window?.setType(info: false)
|
||||||
|
window?.progressView?.labelTitle.stringValue = "alert.composer_failure.title".localized
|
||||||
|
window?.progressView?.labelDescription.stringValue = "alert.composer_failure.info".localized
|
||||||
|
window = nil
|
||||||
|
noLongerBusy()
|
||||||
|
completion(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
phpmon/Domain/Menu/MainMenu+Switcher.swift
Normal file
84
phpmon/Domain/Menu/MainMenu+Switcher.swift
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// MainMenu+PhpSwitcherDelegate.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 08/02/2022.
|
||||||
|
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension MainMenu {
|
||||||
|
|
||||||
|
// MARK: - PhpSwitcherDelegate
|
||||||
|
|
||||||
|
func switcherDidStartSwitching(to version: String) {}
|
||||||
|
|
||||||
|
func switcherDidCompleteSwitch(to version: String) {
|
||||||
|
// Update the PHP version
|
||||||
|
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
||||||
|
|
||||||
|
// Ensure the config watcher gets reloaded
|
||||||
|
App.shared.handlePhpConfigWatcher()
|
||||||
|
|
||||||
|
// Mark as no longer busy
|
||||||
|
PhpEnv.shared.isBusy = false
|
||||||
|
|
||||||
|
// Reload the site list
|
||||||
|
self.reloadSiteListData()
|
||||||
|
|
||||||
|
// Perform UI updates on main thread
|
||||||
|
DispatchQueue.main.async { [self] in
|
||||||
|
updatePhpVersionInStatusBar()
|
||||||
|
rebuild()
|
||||||
|
|
||||||
|
if !PhpEnv.shared.validate(version) {
|
||||||
|
self.suggestFixMyValet(failed: version)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run composer updates
|
||||||
|
if Preferences.isEnabled(.autoComposerGlobalUpdateAfterSwitch) {
|
||||||
|
self.updateGlobalDependencies(notify: false, completion: { _ in
|
||||||
|
self.notifyAboutVersionChange(to: version)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.notifyAboutVersionChange(to: version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update stats
|
||||||
|
Stats.incrementSuccessfulSwitchCount()
|
||||||
|
Stats.evaluateSponsorMessageShouldBeDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func suggestFixMyValet(failed version: String) {
|
||||||
|
let outcome = Alert.present(
|
||||||
|
messageText: "alert.php_switch_failed.title".localized(version),
|
||||||
|
informativeText: "alert.php_switch_failed.info".localized(version),
|
||||||
|
buttonTitle: "alert.php_switch_failed.confirm".localized,
|
||||||
|
secondButtonTitle: "alert.php_switch_failed.cancel".localized, style: .informational)
|
||||||
|
if outcome {
|
||||||
|
MainMenu.shared.fixMyValet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func reloadSiteListData() {
|
||||||
|
if let window = App.shared.siteListWindowController {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
window.contentVC.reloadSites()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Valet.shared.reloadSites()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func notifyAboutVersionChange(to version: String) {
|
||||||
|
LocalNotification.send(
|
||||||
|
title: String(format: "notification.version_changed_title".localized, version),
|
||||||
|
subtitle: String(format: "notification.version_changed_desc".localized, version)
|
||||||
|
)
|
||||||
|
|
||||||
|
PhpEnv.phpInstall.notifyAboutBrokenPhpFpm()
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate {
|
class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate {
|
||||||
|
|
||||||
static let shared = MainMenu()
|
static let shared = MainMenu()
|
||||||
|
|
||||||
@ -23,12 +23,28 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate {
|
|||||||
// MARK: - UI related
|
// MARK: - UI related
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Update the menu's contents, based on what's going on.
|
Rebuilds the menu (either asynchronously or synchronously).
|
||||||
This will rebuild the entire menu, so this can take a few moments.
|
Defaults to rebuilding the menu asynchronously.
|
||||||
*/
|
*/
|
||||||
func rebuild() {
|
func rebuild(async: Bool = true) {
|
||||||
|
if !async {
|
||||||
|
self.rebuildMenu()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Update the menu item on the main thread
|
// Update the menu item on the main thread
|
||||||
DispatchQueue.main.async { [self] in
|
DispatchQueue.main.async { [self] in
|
||||||
|
self.rebuildMenu()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Update the menu's contents, based on what's going on.
|
||||||
|
This will rebuild the entire menu, so this can take a few moments.
|
||||||
|
|
||||||
|
Use `rebuild(async:)` to ensure the rebuilding happens in the background.
|
||||||
|
*/
|
||||||
|
private func rebuildMenu() {
|
||||||
// Create a new menu
|
// Create a new menu
|
||||||
let menu = StatusMenu()
|
let menu = StatusMenu()
|
||||||
|
|
||||||
@ -61,7 +77,6 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate {
|
|||||||
statusItem.menu = menu
|
statusItem.menu = menu
|
||||||
statusItem.menu?.delegate = self
|
statusItem.menu?.delegate = self
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the status bar image based on a version string.
|
Sets the status bar image based on a version string.
|
||||||
@ -87,6 +102,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate {
|
|||||||
|
|
||||||
// MARK: - User Interface
|
// MARK: - User Interface
|
||||||
|
|
||||||
|
/** Reloads which PHP versions is currently active. */
|
||||||
@objc func refreshActiveInstallation() {
|
@objc func refreshActiveInstallation() {
|
||||||
if !PhpEnv.shared.isBusy {
|
if !PhpEnv.shared.isBusy {
|
||||||
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
||||||
@ -96,12 +112,38 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Updates the icon (refresh icon) and rebuilds the menu. */
|
||||||
@objc func updatePhpVersionInStatusBar() {
|
@objc func updatePhpVersionInStatusBar() {
|
||||||
refreshIcon()
|
refreshIcon()
|
||||||
rebuild()
|
rebuild()
|
||||||
}
|
}
|
||||||
|
|
||||||
func refreshIcon() {
|
/**
|
||||||
|
Reloads the menu in the foreground.
|
||||||
|
This mimics the exact behaviours of `asyncExecution` as set in the method below.
|
||||||
|
*/
|
||||||
|
@objc func reloadPhpMonitorMenuInForeground() {
|
||||||
|
refreshActiveInstallation()
|
||||||
|
refreshIcon()
|
||||||
|
rebuild(async: false)
|
||||||
|
NotificationCenter.default.post(name: Events.ServicesUpdated, object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reloads the menu in the background, using `asyncExecution`. */
|
||||||
|
@objc func reloadPhpMonitorMenuInBackground() {
|
||||||
|
asyncExecution({
|
||||||
|
// This automatically reloads the menu
|
||||||
|
Log.info("Reloading information about the PHP installation (in the background)...")
|
||||||
|
}, behaviours: [
|
||||||
|
.setsBusyUI,
|
||||||
|
.reloadsPhpInstallation,
|
||||||
|
.broadcastServicesUpdate,
|
||||||
|
.updatesMenuBarContents
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Refreshes the icon with the PHP version. */
|
||||||
|
@objc func refreshIcon() {
|
||||||
DispatchQueue.main.async { [self] in
|
DispatchQueue.main.async { [self] in
|
||||||
if (App.busy) {
|
if (App.busy) {
|
||||||
setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
||||||
@ -118,20 +160,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func reloadPhpMonitorMenuInBackground() {
|
/** Updates the icon to be displayed as busy. */
|
||||||
asyncExecution {
|
|
||||||
// This automatically reloads the menu
|
|
||||||
Log.info("Reloading information about the PHP installation (in the background)...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func reloadPhpMonitorMenu() {
|
|
||||||
asyncExecution {
|
|
||||||
// This automatically reloads the menu
|
|
||||||
Log.info("Reloading information about the PHP installation...")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func setBusyImage() {
|
@objc func setBusyImage() {
|
||||||
DispatchQueue.main.async { [self] in
|
DispatchQueue.main.async { [self] in
|
||||||
setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
||||||
@ -282,66 +311,23 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate {
|
|||||||
@objc func switchToPhpVersion(_ version: String) {
|
@objc func switchToPhpVersion(_ version: String) {
|
||||||
setBusyImage()
|
setBusyImage()
|
||||||
PhpEnv.shared.isBusy = true
|
PhpEnv.shared.isBusy = true
|
||||||
|
PhpEnv.shared.delegate = self
|
||||||
|
PhpEnv.shared.delegate?.switcherDidStartSwitching(to: version)
|
||||||
|
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
// Update the PHP version in the status bar
|
|
||||||
updatePhpVersionInStatusBar()
|
|
||||||
|
|
||||||
// Update the menu
|
|
||||||
rebuild()
|
|
||||||
|
|
||||||
let sendLocalNotification = {
|
|
||||||
LocalNotification.send(
|
|
||||||
title: String(format: "notification.version_changed_title".localized, version),
|
|
||||||
subtitle: String(format: "notification.version_changed_desc".localized, version)
|
|
||||||
)
|
|
||||||
PhpEnv.phpInstall.notifyAboutBrokenPhpFpm()
|
|
||||||
}
|
|
||||||
|
|
||||||
let completion = {
|
|
||||||
// Fire off the delegate method
|
|
||||||
PhpEnv.shared.delegate?.switcherDidCompleteSwitch()
|
|
||||||
|
|
||||||
// Mark as no longer busy
|
|
||||||
PhpEnv.shared.isBusy = false
|
|
||||||
|
|
||||||
// Perform UI updates on main thread
|
|
||||||
DispatchQueue.main.async { [self] in
|
|
||||||
updatePhpVersionInStatusBar()
|
updatePhpVersionInStatusBar()
|
||||||
rebuild()
|
rebuild()
|
||||||
|
|
||||||
if !PhpEnv.shared.validate(version) {
|
|
||||||
let outcome = Alert.present(
|
|
||||||
messageText: "alert.php_switch_failed.title".localized(version),
|
|
||||||
informativeText: "alert.php_switch_failed.info".localized(version),
|
|
||||||
buttonTitle: "alert.php_switch_failed.confirm".localized,
|
|
||||||
secondButtonTitle: "alert.php_switch_failed.cancel".localized, style: .informational)
|
|
||||||
if outcome {
|
|
||||||
MainMenu.shared.fixMyValet()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run composer updates
|
|
||||||
if Preferences.isEnabled(.autoComposerGlobalUpdateAfterSwitch) {
|
|
||||||
self.updateGlobalDependencies(notify: false, completion: { _ in sendLocalNotification() })
|
|
||||||
} else {
|
|
||||||
sendLocalNotification()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update stats
|
|
||||||
Stats.incrementSuccessfulSwitchCount()
|
|
||||||
Stats.evaluateSponsorMessageShouldBeDisplayed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PhpEnv.switcher.performSwitch(
|
PhpEnv.switcher.performSwitch(
|
||||||
to: version,
|
to: version,
|
||||||
completion: completion
|
completion: {
|
||||||
|
PhpEnv.shared.delegate?.switcherDidCompleteSwitch(to: version)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Menu Item Functionality
|
||||||
|
|
||||||
@objc func openAbout() {
|
@objc func openAbout() {
|
||||||
NSApplication.shared.activate(ignoringOtherApps: true)
|
NSApplication.shared.activate(ignoringOtherApps: true)
|
||||||
NSApplication.shared.orderFrontStandardAboutPanel()
|
NSApplication.shared.orderFrontStandardAboutPanel()
|
||||||
@ -374,91 +360,4 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate {
|
|||||||
// When the menu is closed, allow the shortcut to work again
|
// When the menu is closed, allow the shortcut to work again
|
||||||
App.shared.shortcutHotkey?.isPaused = false
|
App.shared.shortcutHotkey?.isPaused = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private Methods
|
|
||||||
|
|
||||||
/**
|
|
||||||
Updates the global dependencies and runs the completion callback when done.
|
|
||||||
*/
|
|
||||||
private func updateGlobalDependencies(notify: Bool, completion: @escaping (Bool) -> Void) {
|
|
||||||
if !Shell.fileExists("/usr/local/bin/composer") {
|
|
||||||
Alert.notify(
|
|
||||||
message: "alert.composer_missing.title".localized,
|
|
||||||
info: "alert.composer_missing.info".localized
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PhpEnv.shared.isBusy = true
|
|
||||||
setBusyImage()
|
|
||||||
self.rebuild()
|
|
||||||
|
|
||||||
let noLongerBusy = {
|
|
||||||
PhpEnv.shared.isBusy = false
|
|
||||||
DispatchQueue.main.async { [self] in
|
|
||||||
self.updatePhpVersionInStatusBar()
|
|
||||||
self.rebuild()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var window: ProgressWindowController? = ProgressWindowController.display(
|
|
||||||
title: "alert.composer_progress.title".localized,
|
|
||||||
description: "alert.composer_progress.info".localized
|
|
||||||
)
|
|
||||||
window?.setType(info: true)
|
|
||||||
|
|
||||||
DispatchQueue.global(qos: .userInitiated).async {
|
|
||||||
let task = Shell.user.createTask(
|
|
||||||
for: "/usr/local/bin/composer global update", requiresPath: true
|
|
||||||
)
|
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
window?.addToConsole("/usr/local/bin/composer global update\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
Shell.captureOutput(
|
|
||||||
task,
|
|
||||||
didReceiveStdOutData: { string in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
window?.addToConsole(string)
|
|
||||||
}
|
|
||||||
Log.perf("\(string.trimmingCharacters(in: .newlines))")
|
|
||||||
},
|
|
||||||
didReceiveStdErrData: { string in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
window?.addToConsole(string)
|
|
||||||
}
|
|
||||||
Log.perf("\(string.trimmingCharacters(in: .newlines))")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
task.launch()
|
|
||||||
task.waitUntilExit()
|
|
||||||
Shell.haltCapturingOutput(task)
|
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
if task.terminationStatus <= 0 {
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
|
||||||
window?.close()
|
|
||||||
if (notify) {
|
|
||||||
LocalNotification.send(
|
|
||||||
title: "alert.composer_success.title".localized,
|
|
||||||
subtitle: "alert.composer_success.info".localized
|
|
||||||
)
|
|
||||||
}
|
|
||||||
window = nil
|
|
||||||
noLongerBusy()
|
|
||||||
completion(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
window?.setType(info: false)
|
|
||||||
window?.progressView?.labelTitle.stringValue = "alert.composer_failure.title".localized
|
|
||||||
window?.progressView?.labelDescription.stringValue = "alert.composer_failure.info".localized
|
|
||||||
window = nil
|
|
||||||
noLongerBusy()
|
|
||||||
completion(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ class StatusMenu : NSMenu {
|
|||||||
servicesMenu.addItem(NSMenuItem.separator())
|
servicesMenu.addItem(NSMenuItem.separator())
|
||||||
servicesMenu.addItem(HeaderView.asMenuItem(text: "mi_manual_actions".localized))
|
servicesMenu.addItem(HeaderView.asMenuItem(text: "mi_manual_actions".localized))
|
||||||
|
|
||||||
servicesMenu.addItem(NSMenuItem(title: "mi_php_refresh".localized, action: #selector(MainMenu.reloadPhpMonitorMenu), keyEquivalent: "r"))
|
servicesMenu.addItem(NSMenuItem(title: "mi_php_refresh".localized, action: #selector(MainMenu.reloadPhpMonitorMenuInForeground), keyEquivalent: "r"))
|
||||||
|
|
||||||
for item in servicesMenu.items {
|
for item in servicesMenu.items {
|
||||||
item.target = MainMenu.shared
|
item.target = MainMenu.shared
|
||||||
|
@ -40,8 +40,8 @@ class PhpConfigWatcher {
|
|||||||
self.addWatcher(for: self.url.appendingPathComponent("conf.d/\(file)"), eventMask: .write)
|
self.addWatcher(for: self.url.appendingPathComponent("conf.d/\(file)"), eventMask: .write)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info("A watcher exists for the following config paths:")
|
Log.perf("A watcher exists for the following config paths:")
|
||||||
Log.info(self.watchers.map({ watcher in
|
Log.perf(self.watchers.map({ watcher in
|
||||||
return watcher.url.relativePath
|
return watcher.url.relativePath
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ class PhpConfigWatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func disable() {
|
func disable() {
|
||||||
Log.info("Turning off existing watchers...")
|
Log.perf("Turning off all individual existing watchers...")
|
||||||
self.watchers.forEach { (watcher) in
|
self.watchers.forEach { (watcher) in
|
||||||
watcher.stopMonitoring()
|
watcher.stopMonitoring()
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user