mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-08 04:20:07 +02:00
👌 Prevent crash when refresh and switcher run at same time
This commit is contained in:
@ -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 = "<group>"; };
|
||||
C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+ActivationPolicy.swift"; sourceTree = "<group>"; };
|
||||
C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+GlobalHotkey.swift"; sourceTree = "<group>"; };
|
||||
C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Startup.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>"; };
|
||||
C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = "<group>"; };
|
||||
@ -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 */,
|
||||
|
102
phpmon/Domain/Menu/MainMenu+Startup.swift
Normal file
102
phpmon/Domain/Menu/MainMenu+Startup.swift
Normal file
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user