diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 09cb6c2..c4a4f98 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -120,6 +120,7 @@ C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */; }; C4B97B7B275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */; }; C4B97B7C275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */; }; + C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */; }; C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; C4C8E81B276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; @@ -260,6 +261,7 @@ C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+MenuOutlets.swift"; sourceTree = ""; }; C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+ActivationPolicy.swift"; sourceTree = ""; }; C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+GlobalHotkey.swift"; sourceTree = ""; }; + C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Startup.swift"; sourceTree = ""; }; C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "App+ConfigWatch.swift"; sourceTree = ""; }; C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpConfigWatcher.swift; sourceTree = ""; }; C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = ""; }; @@ -480,6 +482,7 @@ isa = PBXGroup; children = ( C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */, + C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */, C47331A1247093B7009A0597 /* StatusMenu.swift */, C48D0C9525CC80B100CC7490 /* HeaderView.swift */, C48D0C9925CC888B00CC7490 /* HeaderView.xib */, @@ -844,6 +847,7 @@ C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */, C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */, C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */, + C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */, C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */, C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */, C464ADAC275A7A3F003FCD53 /* SiteListWC.swift in Sources */, diff --git a/phpmon/Domain/Menu/MainMenu+Startup.swift b/phpmon/Domain/Menu/MainMenu+Startup.swift new file mode 100644 index 0000000..8dd7494 --- /dev/null +++ b/phpmon/Domain/Menu/MainMenu+Startup.swift @@ -0,0 +1,102 @@ +// +// MainMenu+Startup.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 03/01/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Cocoa + +extension MainMenu { + /** + Kick off the startup of the rendering of the main menu. + */ + func startup() { + // Start with the icon + setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!) + + // Perform environment boot checks + DispatchQueue.global(qos: .userInitiated).async { [unowned self] in + Startup().checkEnvironment(success: { onEnvironmentPass() }, + failure: { onEnvironmentFail() } + ) + } + } + + /** + When the environment is all clear and the app can run, let's go. + */ + private func onEnvironmentPass() { + PhpEnv.detectPhpVersions() + + if HomebrewDiagnostics.shared.errors.contains(.aliasConflict) { + DispatchQueue.main.async { + Alert.notify( + message: "alert.php_alias_conflict.title".localized, + info: "alert.php_alias_conflict.info".localized, + style: .critical + ) + } + } + + updatePhpVersionInStatusBar() + + Log.info("Determining broken PHP-FPM...") + // Attempt to find out if PHP-FPM is broken + let installation = PhpEnv.phpInstall + installation.notifyAboutBrokenPhpFpm() + + // Set up the config watchers on launch (these are automatically updated via delegate methods if the user switches) + Log.info("Setting up watchers...") + App.shared.handlePhpConfigWatcher() + + Log.info("Detecting applications...") + // Attempt to load list of applications + App.shared.detectedApplications = Application.detectPresetApplications() + let appNames = App.shared.detectedApplications.map { app in + return app.name + } + Log.info("Detected applications: \(appNames)") + + // Load the global hotkey + App.shared.loadGlobalHotkey() + + // Attempt to find out more info about Valet + Log.info("PHP Monitor has extracted the version number of Valet: \(Valet.shared.version)") + Valet.shared.validateVersion() + Valet.shared.startPreloadingSites() + 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( + timeInterval: 60, + target: self, + selector: #selector(refreshActiveInstallation), + userInfo: nil, + repeats: true + ) + } + } + + /** + When the environment is not OK, present an alert to inform the user. + */ + private func onEnvironmentFail() { + DispatchQueue.main.async { [self] in + let close = Alert.present( + messageText: "alert.cannot_start.title".localized, + informativeText: "alert.cannot_start.info".localized, + buttonTitle: "alert.cannot_start.close".localized, + secondButtonTitle: "alert.cannot_start.retry".localized + ) + + if (close) { + exit(1) + } + + startup() + } + } +} diff --git a/phpmon/Domain/Menu/MainMenu.swift b/phpmon/Domain/Menu/MainMenu.swift index 6abfa62..7cda0f7 100644 --- a/phpmon/Domain/Menu/MainMenu.swift +++ b/phpmon/Domain/Menu/MainMenu.swift @@ -22,97 +22,6 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { // MARK: - UI related - /** - Kick off the startup of the rendering of the main menu. - */ - func startup() { - // Start with the icon - setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!) - - // Perform environment boot checks - DispatchQueue.global(qos: .userInitiated).async { [unowned self] in - Startup().checkEnvironment(success: { onEnvironmentPass() }, - failure: { onEnvironmentFail() } - ) - } - } - - /** - When the environment is all clear and the app can run, let's go. - */ - private func onEnvironmentPass() { - PhpEnv.detectPhpVersions() - - if HomebrewDiagnostics.shared.errors.contains(.aliasConflict) { - DispatchQueue.main.async { - Alert.notify( - message: "alert.php_alias_conflict.title".localized, - info: "alert.php_alias_conflict.info".localized, - style: .critical - ) - } - } - - updatePhpVersionInStatusBar() - - Log.info("Determining broken PHP-FPM...") - // Attempt to find out if PHP-FPM is broken - let installation = PhpEnv.phpInstall - installation.notifyAboutBrokenPhpFpm() - - // Set up the config watchers on launch (these are automatically updated via delegate methods if the user switches) - Log.info("Setting up watchers...") - App.shared.handlePhpConfigWatcher() - - Log.info("Detecting applications...") - // Attempt to load list of applications - App.shared.detectedApplications = Application.detectPresetApplications() - let appNames = App.shared.detectedApplications.map { app in - return app.name - } - Log.info("Detected applications: \(appNames)") - - // Load the global hotkey - App.shared.loadGlobalHotkey() - - // Attempt to find out more info about Valet - Log.info("PHP Monitor has extracted the version number of Valet: \(Valet.shared.version)") - Valet.shared.validateVersion() - Valet.shared.startPreloadingSites() - 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( - timeInterval: 60, - target: self, - selector: #selector(refreshActiveInstallation), - userInfo: nil, - repeats: true - ) - } - } - - /** - When the environment is not OK, present an alert to inform the user. - */ - private func onEnvironmentFail() { - DispatchQueue.main.async { [self] in - let close = Alert.present( - messageText: "alert.cannot_start.title".localized, - informativeText: "alert.cannot_start.info".localized, - buttonTitle: "alert.cannot_start.close".localized, - secondButtonTitle: "alert.cannot_start.retry".localized - ) - - if (close) { - exit(1) - } - - startup() - } - } - /** Update the menu's contents, based on what's going on. */ @@ -203,8 +112,12 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { // MARK: - User Interface @objc func refreshActiveInstallation() { - PhpEnv.shared.currentInstall = ActivePhpInstallation() - updatePhpVersionInStatusBar() + if !PhpEnv.shared.isBusy { + PhpEnv.shared.currentInstall = ActivePhpInstallation() + updatePhpVersionInStatusBar() + } else { + Log.perf("Skipping version refresh due to busy status") + } } @objc func updatePhpVersionInStatusBar() { @@ -342,86 +255,10 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { } } - @objc func updateComposerDependencies() { + @objc func updateGlobalComposerDependencies() { self.updateGlobalDependencies(notify: true, completion: { _ in }) } - func updateGlobalDependencies(notify: Bool, completion: @escaping (Bool) -> Void) { - PhpEnv.shared.isBusy = true - setBusyImage() - self.update() - - let noLongerBusy = { - PhpEnv.shared.isBusy = false - DispatchQueue.main.async { [self] in - self.updatePhpVersionInStatusBar() - self.update() - } - } - - 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 output = Shell.user.executeSynchronously( - "composer global update", requiresPath: true - ) - - let task = Shell.user.createTask(for: "composer global update", requiresPath: true) - - DispatchQueue.main.async { - window?.addToConsole("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 output.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) - } - } - } - } - @objc func openActiveConfigFolder() { if (PhpEnv.phpInstall.version.error) { // php version was not identified @@ -515,4 +352,85 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { // When the menu is closed, allow the shortcut to work again App.shared.shortcutHotkey?.isPaused = false } + + // MARK: - Private Methods + + /** + + */ + private func updateGlobalDependencies(notify: Bool, completion: @escaping (Bool) -> Void) { + PhpEnv.shared.isBusy = true + setBusyImage() + self.update() + + let noLongerBusy = { + PhpEnv.shared.isBusy = false + DispatchQueue.main.async { [self] in + self.updatePhpVersionInStatusBar() + self.update() + } + } + + 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 output = Shell.user.executeSynchronously( + "composer global update", requiresPath: true + ) + + let task = Shell.user.createTask(for: "composer global update", requiresPath: true) + + DispatchQueue.main.async { + window?.addToConsole("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 output.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) + } + } + } + } } diff --git a/phpmon/Domain/Menu/StatusMenu.swift b/phpmon/Domain/Menu/StatusMenu.swift index 58facdd..2644681 100644 --- a/phpmon/Domain/Menu/StatusMenu.swift +++ b/phpmon/Domain/Menu/StatusMenu.swift @@ -92,7 +92,7 @@ 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: PhpEnv.shared.isBusy ? nil : #selector(MainMenu.updateComposerDependencies), keyEquivalent: "")) + self.addItem(NSMenuItem(title: "mi_update_global_composer".localized, action: PhpEnv.shared.isBusy ? nil : #selector(MainMenu.updateGlobalComposerDependencies), keyEquivalent: "")) if (PhpEnv.shared.isBusy) { return