1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-07 03:50:08 +02:00

👌 Allow PHP Monitor to run without linked PHP

This commit is contained in:
2023-01-12 00:04:54 +01:00
parent 44800a03a1
commit 17efb50872
10 changed files with 155 additions and 19 deletions

View File

@ -16,7 +16,6 @@ class Homebrew {
}
guard let install = PhpEnv.phpInstall else {
Log.info("Assuming the formula is `php` since none seems to be linked.")
return HomebrewFormula("php", elevated: true)
}

View File

@ -37,13 +37,20 @@ class ActivePhpInstallation {
// MARK: - Initializer
public static func load() -> ActivePhpInstallation? {
if !FileSystem.fileExists(Paths.phpConfig) {
return nil
}
return ActivePhpInstallation()
}
init() {
// Show information about the current version
do {
try determineVersion()
} 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

View File

@ -13,7 +13,7 @@ class PhpEnv {
// MARK: - Initializer
init() {
self.currentInstall = ActivePhpInstallation()
self.currentInstall = ActivePhpInstallation.load()
}
func determinePhpAlias() async {
@ -90,9 +90,17 @@ class PhpEnv {
public func detectPhpVersions() async -> [String] {
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(
from: files.components(separatedBy: "\n"),
supported: Constants.ValetSupportedPhpVersionMatrix[Valet.shared.version.major] ?? []
supported: supported
)
// Make sure the aliased version is detected

View File

@ -99,12 +99,96 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
startup procedure.
*/
func applicationDidFinishLaunching(_ aNotification: Notification) {
self.watchHomebrewBinFolder()
/*
// Make sure notifications will work
setupNotifications()
Task { // Make sure the menu performs its initial checks
await paths.loadUser()
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")
}
}

View File

@ -99,6 +99,7 @@ class Startup {
buttonText: "alert.homebrew_missing.quit".localized,
requiresAppRestart: true
),
/*
// =================================================================================
// The PHP binary must exist.
// =================================================================================
@ -109,6 +110,7 @@ class Startup {
subtitleText: "startup.errors.php_binary.subtitle".localized,
descriptionText: "startup.errors.php_binary.desc".localized(Paths.php)
),
*/
// =================================================================================
// 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)
// =================================================================================
/*
EnvironmentCheck(
command: {
return await Shell.pipe("valet --version").out
@ -264,5 +267,6 @@ class Startup {
subtitleText: "startup.errors.valet_version_not_supported.subtitle".localized,
descriptionText: "startup.errors.valet_version_not_supported.desc".localized
)
*/
]
}

View File

@ -22,7 +22,7 @@ class Valet {
static let shared = Valet()
/// The version of Valet that was detected.
var version: VersionNumber! = nil
var version: VersionNumber? = nil
/// The Valet configuration file.
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.
*/
public func evaluateFeatureSupport() {
guard let version = self.version else {
Log.err("Cannot determine features, as the version was not determined.")
return
}
switch version.major {
case 2:
Log.info("You are running Valet v2. Support for site isolation is disabled.")
@ -159,12 +164,21 @@ class Valet {
installed is not recent enough.
*/
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
Valet.shared.evaluateFeatureSupport()
// 2. Notify user if the version is too old (but major version is OK)
if version.text.versionCompare(Constants.MinimumRecommendedValetVersion) == .orderedAscending {
let version = version!
let recommended = Constants.MinimumRecommendedValetVersion
Log.warn("Valet version \(version.text) is too old! (recommended: \(recommended))")
Task { @MainActor in

View File

@ -71,7 +71,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
/** Reloads which PHP versions is currently active. */
@objc func refreshActiveInstallation() {
if !PhpEnv.shared.isBusy {
PhpEnv.shared.currentInstall = ActivePhpInstallation()
PhpEnv.shared.currentInstall = ActivePhpInstallation.load()
updatePhpVersionInStatusBar()
} else {
Log.perf("Skipping version refresh due to busy status!")

View File

@ -13,7 +13,18 @@ import Cocoa
extension StatusMenu {
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"]
return addItems(brokenMenuItems.map { NSMenuItem(title: $0.localized) })
}
@ -30,7 +41,13 @@ extension StatusMenu {
return
}
if PhpEnv.shared.availablePhpVersions.isEmpty { return }
if PhpEnv.shared.availablePhpVersions.isEmpty {
return
}
if PhpEnv.shared.currentInstall == nil {
return
}
addSwitchToPhpMenuItems()
self.addItem(NSMenuItem.separator())

View File

@ -12,27 +12,27 @@ class StatusMenu: NSMenu {
addPhpVersionMenuItems()
addItem(NSMenuItem.separator())
if Preferences.isEnabled(.displayGlobalVersionSwitcher) {
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayGlobalVersionSwitcher) {
addPhpActionMenuItems()
addItem(NSMenuItem.separator())
}
if Preferences.isEnabled(.displayServicesManager) {
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayServicesManager) {
addServicesManagerMenuItem()
addItem(NSMenuItem.separator())
}
if Preferences.isEnabled(.displayValetIntegration) {
if Valet.shared.version != nil && Preferences.isEnabled(.displayValetIntegration) {
addValetMenuItems()
addItem(NSMenuItem.separator())
}
if Preferences.isEnabled(.displayPhpConfigFinder) {
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayPhpConfigFinder) {
addConfigurationMenuItems()
addItem(NSMenuItem.separator())
}
if Preferences.isEnabled(.displayComposerToolkit) {
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayComposerToolkit) {
addComposerMenuItems()
addItem(NSMenuItem.separator())
}
@ -41,12 +41,12 @@ class StatusMenu: NSMenu {
return
}
if Preferences.isEnabled(.displayLimitsWidget) {
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayLimitsWidget) {
addStatsMenuItem()
addItem(NSMenuItem.separator())
}
if Preferences.isEnabled(.displayExtensions) {
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayExtensions) {
addExtensionsMenuItems()
NSMenuItem.separator()
@ -55,11 +55,11 @@ class StatusMenu: NSMenu {
addPhpDoctorMenuItem()
if Preferences.isEnabled(.displayPresets) {
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayPresets) {
addPresetsMenuItem()
}
if Preferences.isEnabled(.displayMisc) {
if PhpEnv.phpInstall != nil && Preferences.isEnabled(.displayMisc) {
addFirstAidAndServicesMenuItems()
}

View File

@ -16,6 +16,9 @@
"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_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_active_services" = "Active Services";