mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-12 14:00:08 +02:00
👌 Allow PHP Monitor to run without linked PHP
This commit is contained in:
@@ -16,7 +16,6 @@ class Homebrew {
|
|||||||
}
|
}
|
||||||
|
|
||||||
guard let install = PhpEnv.phpInstall else {
|
guard let install = PhpEnv.phpInstall else {
|
||||||
Log.info("Assuming the formula is `php` since none seems to be linked.")
|
|
||||||
return HomebrewFormula("php", elevated: true)
|
return HomebrewFormula("php", elevated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -37,13 +37,20 @@ class ActivePhpInstallation {
|
|||||||
|
|
||||||
// MARK: - Initializer
|
// MARK: - Initializer
|
||||||
|
|
||||||
|
public static func load() -> ActivePhpInstallation? {
|
||||||
|
if !FileSystem.fileExists(Paths.phpConfig) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ActivePhpInstallation()
|
||||||
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
// Show information about the current version
|
// Show information about the current version
|
||||||
do {
|
do {
|
||||||
try determineVersion()
|
try determineVersion()
|
||||||
} catch {
|
} catch {
|
||||||
// TODO: In future versions of PHP Monitor, this should not crash
|
fatalError("Could not determine or parse PHP version; aborting!")
|
||||||
fatalError("Could not determine or parse PHP version; aborting")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the list of ini files that are loaded
|
// Initialize the list of ini files that are loaded
|
||||||
|
@@ -13,7 +13,7 @@ class PhpEnv {
|
|||||||
// MARK: - Initializer
|
// MARK: - Initializer
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
self.currentInstall = ActivePhpInstallation()
|
self.currentInstall = ActivePhpInstallation.load()
|
||||||
}
|
}
|
||||||
|
|
||||||
func determinePhpAlias() async {
|
func determinePhpAlias() async {
|
||||||
@@ -90,9 +90,17 @@ class PhpEnv {
|
|||||||
public func detectPhpVersions() async -> [String] {
|
public func detectPhpVersions() async -> [String] {
|
||||||
let files = await Shell.pipe("ls \(Paths.optPath) | grep php@").out
|
let files = await Shell.pipe("ls \(Paths.optPath) | grep php@").out
|
||||||
|
|
||||||
|
let supported: [String] = {
|
||||||
|
guard let version = Valet.shared.version else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return Constants.ValetSupportedPhpVersionMatrix[version.major] ?? []
|
||||||
|
}()
|
||||||
|
|
||||||
var versionsOnly = await extractPhpVersions(
|
var versionsOnly = await extractPhpVersions(
|
||||||
from: files.components(separatedBy: "\n"),
|
from: files.components(separatedBy: "\n"),
|
||||||
supported: Constants.ValetSupportedPhpVersionMatrix[Valet.shared.version.major] ?? []
|
supported: supported
|
||||||
)
|
)
|
||||||
|
|
||||||
// Make sure the aliased version is detected
|
// Make sure the aliased version is detected
|
||||||
|
@@ -99,12 +99,96 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
|||||||
startup procedure.
|
startup procedure.
|
||||||
*/
|
*/
|
||||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||||
|
self.watchHomebrewBinFolder()
|
||||||
|
/*
|
||||||
// Make sure notifications will work
|
// Make sure notifications will work
|
||||||
setupNotifications()
|
setupNotifications()
|
||||||
Task { // Make sure the menu performs its initial checks
|
Task { // Make sure the menu performs its initial checks
|
||||||
await paths.loadUser()
|
await paths.loadUser()
|
||||||
await menu.startup()
|
await menu.startup()
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func watchHomebrewBinFolder() {
|
||||||
|
Log.info("Watching Homebrew's bin folder")
|
||||||
|
FSWatch2.shared = FSWatch2(
|
||||||
|
for: URL(fileURLWithPath: Paths.binPath),
|
||||||
|
eventMask: .all,
|
||||||
|
onChange: {
|
||||||
|
print("Something has changed")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FSWatch2 {
|
||||||
|
public static var shared: FSWatch2! = nil
|
||||||
|
|
||||||
|
let queue = DispatchQueue(label: "FSWatch2Queue", attributes: .concurrent)
|
||||||
|
|
||||||
|
var lastUpdate: TimeInterval?
|
||||||
|
var linked: Bool
|
||||||
|
|
||||||
|
private var fileDescriptor: CInt = -1
|
||||||
|
private var dispatchSource: DispatchSourceFileSystemObject?
|
||||||
|
|
||||||
|
internal let url: URL
|
||||||
|
|
||||||
|
init(for url: URL, eventMask: DispatchSource.FileSystemEvent, onChange: () -> Void) {
|
||||||
|
self.url = url
|
||||||
|
|
||||||
|
self.linked = FileSystem.fileExists(Paths.php)
|
||||||
|
print("Initial PHP linked state: \(linked)")
|
||||||
|
|
||||||
|
fileDescriptor = open(url.path, O_EVTONLY)
|
||||||
|
|
||||||
|
dispatchSource = DispatchSource.makeFileSystemObjectSource(
|
||||||
|
fileDescriptor: fileDescriptor,
|
||||||
|
eventMask: eventMask,
|
||||||
|
queue: self.queue
|
||||||
|
)
|
||||||
|
|
||||||
|
dispatchSource?.setEventHandler(handler: {
|
||||||
|
let distance = self.lastUpdate?.distance(to: Date().timeIntervalSince1970)
|
||||||
|
|
||||||
|
if distance == nil || distance != nil && distance! > 1.00 {
|
||||||
|
print("FS event fired, checking in 1s, no duplicate FS events will be acted upon")
|
||||||
|
|
||||||
|
self.lastUpdate = Date().timeIntervalSince1970
|
||||||
|
|
||||||
|
Task {
|
||||||
|
await delay(seconds: 1)
|
||||||
|
|
||||||
|
let newLinked = FileSystem.fileExists(Paths.php)
|
||||||
|
|
||||||
|
if newLinked != self.linked {
|
||||||
|
self.linked = newLinked
|
||||||
|
|
||||||
|
Log.info("The status of the PHP binary has changed!")
|
||||||
|
|
||||||
|
if newLinked {
|
||||||
|
Log.info("php is linked")
|
||||||
|
} else {
|
||||||
|
Log.info("php is not linked")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
dispatchSource?.setCancelHandler(handler: { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
close(self.fileDescriptor)
|
||||||
|
self.fileDescriptor = -1
|
||||||
|
self.dispatchSource = nil
|
||||||
|
})
|
||||||
|
|
||||||
|
dispatchSource?.resume()
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
print("deallocing watcher")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -99,6 +99,7 @@ class Startup {
|
|||||||
buttonText: "alert.homebrew_missing.quit".localized,
|
buttonText: "alert.homebrew_missing.quit".localized,
|
||||||
requiresAppRestart: true
|
requiresAppRestart: true
|
||||||
),
|
),
|
||||||
|
/*
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
// The PHP binary must exist.
|
// The PHP binary must exist.
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
@@ -109,6 +110,7 @@ class Startup {
|
|||||||
subtitleText: "startup.errors.php_binary.subtitle".localized,
|
subtitleText: "startup.errors.php_binary.subtitle".localized,
|
||||||
descriptionText: "startup.errors.php_binary.desc".localized(Paths.php)
|
descriptionText: "startup.errors.php_binary.desc".localized(Paths.php)
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
// Make sure we can detect one or more PHP installations.
|
// Make sure we can detect one or more PHP installations.
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
@@ -216,6 +218,7 @@ class Startup {
|
|||||||
// =================================================================================
|
// =================================================================================
|
||||||
// Determine that Valet works correctly (no issues in platform detected)
|
// Determine that Valet works correctly (no issues in platform detected)
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
|
/*
|
||||||
EnvironmentCheck(
|
EnvironmentCheck(
|
||||||
command: {
|
command: {
|
||||||
return await Shell.pipe("valet --version").out
|
return await Shell.pipe("valet --version").out
|
||||||
@@ -264,5 +267,6 @@ class Startup {
|
|||||||
subtitleText: "startup.errors.valet_version_not_supported.subtitle".localized,
|
subtitleText: "startup.errors.valet_version_not_supported.subtitle".localized,
|
||||||
descriptionText: "startup.errors.valet_version_not_supported.desc".localized
|
descriptionText: "startup.errors.valet_version_not_supported.desc".localized
|
||||||
)
|
)
|
||||||
|
*/
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ class Valet {
|
|||||||
static let shared = Valet()
|
static let shared = Valet()
|
||||||
|
|
||||||
/// The version of Valet that was detected.
|
/// The version of Valet that was detected.
|
||||||
var version: VersionNumber! = nil
|
var version: VersionNumber? = nil
|
||||||
|
|
||||||
/// The Valet configuration file.
|
/// The Valet configuration file.
|
||||||
var config: Valet.Configuration!
|
var config: Valet.Configuration!
|
||||||
@@ -142,6 +142,11 @@ class Valet {
|
|||||||
in use. This allows PHP Monitor to do different things when Valet 3.0 is enabled.
|
in use. This allows PHP Monitor to do different things when Valet 3.0 is enabled.
|
||||||
*/
|
*/
|
||||||
public func evaluateFeatureSupport() {
|
public func evaluateFeatureSupport() {
|
||||||
|
guard let version = self.version else {
|
||||||
|
Log.err("Cannot determine features, as the version was not determined.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch version.major {
|
switch version.major {
|
||||||
case 2:
|
case 2:
|
||||||
Log.info("You are running Valet v2. Support for site isolation is disabled.")
|
Log.info("You are running Valet v2. Support for site isolation is disabled.")
|
||||||
@@ -159,12 +164,21 @@ class Valet {
|
|||||||
installed is not recent enough.
|
installed is not recent enough.
|
||||||
*/
|
*/
|
||||||
public func validateVersion() {
|
public func validateVersion() {
|
||||||
|
guard let version = self.version else {
|
||||||
|
Log.err("Cannot validate Valet version if no Valet version was determined.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if PhpEnv.phpInstall == nil {
|
||||||
|
Log.info("Cannot validate Valet version if no PHP version is linked.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Evaluate feature support
|
// 1. Evaluate feature support
|
||||||
Valet.shared.evaluateFeatureSupport()
|
Valet.shared.evaluateFeatureSupport()
|
||||||
|
|
||||||
// 2. Notify user if the version is too old (but major version is OK)
|
// 2. Notify user if the version is too old (but major version is OK)
|
||||||
if version.text.versionCompare(Constants.MinimumRecommendedValetVersion) == .orderedAscending {
|
if version.text.versionCompare(Constants.MinimumRecommendedValetVersion) == .orderedAscending {
|
||||||
let version = version!
|
|
||||||
let recommended = Constants.MinimumRecommendedValetVersion
|
let recommended = Constants.MinimumRecommendedValetVersion
|
||||||
Log.warn("Valet version \(version.text) is too old! (recommended: \(recommended))")
|
Log.warn("Valet version \(version.text) is too old! (recommended: \(recommended))")
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
|
@@ -71,7 +71,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
|||||||
/** Reloads which PHP versions is currently active. */
|
/** 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.load()
|
||||||
updatePhpVersionInStatusBar()
|
updatePhpVersionInStatusBar()
|
||||||
} else {
|
} else {
|
||||||
Log.perf("Skipping version refresh due to busy status!")
|
Log.perf("Skipping version refresh due to busy status!")
|
||||||
|
@@ -13,7 +13,18 @@ import Cocoa
|
|||||||
extension StatusMenu {
|
extension StatusMenu {
|
||||||
|
|
||||||
func addPhpVersionMenuItems() {
|
func addPhpVersionMenuItems() {
|
||||||
if PhpEnv.phpInstall == nil || PhpEnv.phpInstall!.hasErrorState {
|
if PhpEnv.phpInstall == nil {
|
||||||
|
addItem(HeaderView.asMenuItem(text: "⚠️ " + "mi_no_php_linked".localized, minimumWidth: 280))
|
||||||
|
addItems([
|
||||||
|
// TODO: Make sure these buttons do something
|
||||||
|
NSMenuItem.separator(),
|
||||||
|
NSMenuItem(title: "mi_fix_php_link".localized),
|
||||||
|
NSMenuItem(title: "mi_no_php_linked_explain".localized)
|
||||||
|
])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if PhpEnv.phpInstall!.hasErrorState {
|
||||||
let brokenMenuItems = ["mi_php_broken_1", "mi_php_broken_2", "mi_php_broken_3", "mi_php_broken_4"]
|
let brokenMenuItems = ["mi_php_broken_1", "mi_php_broken_2", "mi_php_broken_3", "mi_php_broken_4"]
|
||||||
return addItems(brokenMenuItems.map { NSMenuItem(title: $0.localized) })
|
return addItems(brokenMenuItems.map { NSMenuItem(title: $0.localized) })
|
||||||
}
|
}
|
||||||
@@ -30,7 +41,13 @@ extension StatusMenu {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if PhpEnv.shared.availablePhpVersions.isEmpty { return }
|
if PhpEnv.shared.availablePhpVersions.isEmpty {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if PhpEnv.shared.currentInstall == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
addSwitchToPhpMenuItems()
|
addSwitchToPhpMenuItems()
|
||||||
self.addItem(NSMenuItem.separator())
|
self.addItem(NSMenuItem.separator())
|
||||||
|
@@ -12,27 +12,27 @@ class StatusMenu: NSMenu {
|
|||||||
addPhpVersionMenuItems()
|
addPhpVersionMenuItems()
|
||||||
addItem(NSMenuItem.separator())
|
addItem(NSMenuItem.separator())
|
||||||
|
|
||||||
if Preferences.isEnabled(.displayGlobalVersionSwitcher) {
|
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayGlobalVersionSwitcher) {
|
||||||
addPhpActionMenuItems()
|
addPhpActionMenuItems()
|
||||||
addItem(NSMenuItem.separator())
|
addItem(NSMenuItem.separator())
|
||||||
}
|
}
|
||||||
|
|
||||||
if Preferences.isEnabled(.displayServicesManager) {
|
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayServicesManager) {
|
||||||
addServicesManagerMenuItem()
|
addServicesManagerMenuItem()
|
||||||
addItem(NSMenuItem.separator())
|
addItem(NSMenuItem.separator())
|
||||||
}
|
}
|
||||||
|
|
||||||
if Preferences.isEnabled(.displayValetIntegration) {
|
if Valet.shared.version != nil && Preferences.isEnabled(.displayValetIntegration) {
|
||||||
addValetMenuItems()
|
addValetMenuItems()
|
||||||
addItem(NSMenuItem.separator())
|
addItem(NSMenuItem.separator())
|
||||||
}
|
}
|
||||||
|
|
||||||
if Preferences.isEnabled(.displayPhpConfigFinder) {
|
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayPhpConfigFinder) {
|
||||||
addConfigurationMenuItems()
|
addConfigurationMenuItems()
|
||||||
addItem(NSMenuItem.separator())
|
addItem(NSMenuItem.separator())
|
||||||
}
|
}
|
||||||
|
|
||||||
if Preferences.isEnabled(.displayComposerToolkit) {
|
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayComposerToolkit) {
|
||||||
addComposerMenuItems()
|
addComposerMenuItems()
|
||||||
addItem(NSMenuItem.separator())
|
addItem(NSMenuItem.separator())
|
||||||
}
|
}
|
||||||
@@ -41,12 +41,12 @@ class StatusMenu: NSMenu {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if Preferences.isEnabled(.displayLimitsWidget) {
|
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayLimitsWidget) {
|
||||||
addStatsMenuItem()
|
addStatsMenuItem()
|
||||||
addItem(NSMenuItem.separator())
|
addItem(NSMenuItem.separator())
|
||||||
}
|
}
|
||||||
|
|
||||||
if Preferences.isEnabled(.displayExtensions) {
|
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayExtensions) {
|
||||||
addExtensionsMenuItems()
|
addExtensionsMenuItems()
|
||||||
NSMenuItem.separator()
|
NSMenuItem.separator()
|
||||||
|
|
||||||
@@ -55,11 +55,11 @@ class StatusMenu: NSMenu {
|
|||||||
|
|
||||||
addPhpDoctorMenuItem()
|
addPhpDoctorMenuItem()
|
||||||
|
|
||||||
if Preferences.isEnabled(.displayPresets) {
|
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayPresets) {
|
||||||
addPresetsMenuItem()
|
addPresetsMenuItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
if Preferences.isEnabled(.displayMisc) {
|
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayMisc) {
|
||||||
addFirstAidAndServicesMenuItems()
|
addFirstAidAndServicesMenuItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,6 +16,9 @@
|
|||||||
"mi_php_broken_2" = "Try running `php -v` in your terminal.";
|
"mi_php_broken_2" = "Try running `php -v` in your terminal.";
|
||||||
"mi_php_broken_3" = "You could also try switching to another version.";
|
"mi_php_broken_3" = "You could also try switching to another version.";
|
||||||
"mi_php_broken_4" = "Running `brew reinstall php` (or for the equivalent version) might help.";
|
"mi_php_broken_4" = "Running `brew reinstall php` (or for the equivalent version) might help.";
|
||||||
|
"mi_no_php_linked" = "No PHP version linked!";
|
||||||
|
"mi_fix_php_link" = "Fix Automatically...";
|
||||||
|
"mi_no_php_linked_explain" = "What's This?";
|
||||||
|
|
||||||
"mi_diagnostics" = "Diagnostics";
|
"mi_diagnostics" = "Diagnostics";
|
||||||
"mi_active_services" = "Active Services";
|
"mi_active_services" = "Active Services";
|
||||||
|
Reference in New Issue
Block a user