mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 03:50:08 +02:00
🏗 WIP: Allow unlinked PHP version
This commit is contained in:
@ -9,19 +9,18 @@
|
||||
import Foundation
|
||||
|
||||
class Homebrew {
|
||||
static var fake: Bool = false
|
||||
|
||||
struct Formulae {
|
||||
static var php: HomebrewFormula {
|
||||
if Homebrew.fake {
|
||||
return HomebrewFormula("php", elevated: true)
|
||||
}
|
||||
|
||||
if PhpEnv.shared.homebrewPackage == nil {
|
||||
fatalError("You must either load the HomebrewPackage object or call `fake` on the Homebrew class.")
|
||||
}
|
||||
|
||||
return HomebrewFormula(PhpEnv.phpInstall.formula, elevated: true)
|
||||
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(install.formula, elevated: true)
|
||||
}
|
||||
|
||||
static var nginx: HomebrewFormula {
|
||||
|
@ -45,7 +45,7 @@ class PhpEnv {
|
||||
var cachedPhpInstallations: [String: PhpInstallation] = [:]
|
||||
|
||||
/** Information about the currently linked PHP installation. */
|
||||
var currentInstall: ActivePhpInstallation!
|
||||
var currentInstall: ActivePhpInstallation?
|
||||
|
||||
/**
|
||||
The version that the `php` formula via Brew is aliased to on the current system.
|
||||
@ -57,15 +57,15 @@ class PhpEnv {
|
||||
As such, we take that information from Homebrew.
|
||||
*/
|
||||
static var brewPhpAlias: String {
|
||||
if Homebrew.fake { return "8.2" }
|
||||
if PhpEnv.shared.homebrewPackage == nil { return "8.2" }
|
||||
|
||||
return Self.shared.homebrewPackage.version
|
||||
return PhpEnv.shared.homebrewPackage.version
|
||||
}
|
||||
|
||||
/**
|
||||
The currently linked and active PHP installation.
|
||||
*/
|
||||
static var phpInstall: ActivePhpInstallation {
|
||||
static var phpInstall: ActivePhpInstallation? {
|
||||
return Self.shared.currentInstall
|
||||
}
|
||||
|
||||
@ -170,7 +170,12 @@ class PhpEnv {
|
||||
Validates whether the currently running version matches the provided version.
|
||||
*/
|
||||
public func validate(_ version: String) -> Bool {
|
||||
if self.currentInstall.version.short == version {
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
Log.info("It appears as if no PHP installation is currently active.")
|
||||
return false
|
||||
}
|
||||
|
||||
if install.version.short == version {
|
||||
Log.info("Switching to version \(version) seems to have succeeded. Validation passed.")
|
||||
Log.info("Keeping track that this is the new version!")
|
||||
Stats.persistCurrentGlobalPhpVersion(version: version)
|
||||
@ -186,7 +191,11 @@ class PhpEnv {
|
||||
You can then use the configuration file instance to change values.
|
||||
*/
|
||||
public func getConfigFile(forKey key: String) -> PhpConfigurationFile? {
|
||||
return PhpEnv.phpInstall.iniFiles
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return install.iniFiles
|
||||
.reversed()
|
||||
.first(where: { $0.has(key: key) })
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ public struct TestableConfiguration: Codable {
|
||||
func apply() {
|
||||
Log.separator()
|
||||
Log.info("USING TESTABLE CONFIGURATION...")
|
||||
Homebrew.fake = true
|
||||
Log.separator()
|
||||
Log.info("Applying fake shell...")
|
||||
ActiveShell.useTestable(shellOutput)
|
||||
|
@ -261,7 +261,7 @@ class Startup {
|
||||
},
|
||||
name: "valet version is supported",
|
||||
titleText: "startup.errors.valet_version_not_supported.title".localized,
|
||||
subtitleText: "startup.errors.valet_version_not_supported.subtitle".localized(Valet.shared.version.text),
|
||||
subtitleText: "startup.errors.valet_version_not_supported.subtitle".localized,
|
||||
descriptionText: "startup.errors.valet_version_not_supported.desc".localized
|
||||
)
|
||||
]
|
||||
|
@ -58,8 +58,12 @@ class DomainListPhpCell: NSTableCellView, DomainListCellProtocol {
|
||||
return []
|
||||
}
|
||||
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
return []
|
||||
}
|
||||
|
||||
return PhpEnv.shared.validVersions(for: site.composerPhp).filter({ version in
|
||||
version.short != PhpEnv.phpInstall.version.short
|
||||
version.short != install.version.short
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ extension DomainListVC {
|
||||
|
||||
if site.isolatedPhpVersion != nil {
|
||||
menu.addItem(NSMenuItem(
|
||||
title: "domain_list.use_in_terminal".localized(site.servingPhpVersion),
|
||||
title: "domain_list.use_in_terminal".localized(site.isolatedPhpVersion!.versionNumber.text),
|
||||
action: #selector(self.useInTerminal)
|
||||
))
|
||||
}
|
||||
|
@ -65,8 +65,13 @@ class HomebrewDiagnostics {
|
||||
public static func checkForPhpFpmPoolConflicts() {
|
||||
Log.info("Checking for PHP-FPM pool conflicts...")
|
||||
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
Log.info("Will skip check for conflicts if no PHP version is linked.")
|
||||
return
|
||||
}
|
||||
|
||||
// We'll need to know what the primary PHP version is
|
||||
let primary = PhpEnv.shared.currentInstall.version.short
|
||||
let primary = install.version.short
|
||||
|
||||
// Versions to be handled
|
||||
let switcher = InternalSwitcher()
|
||||
|
@ -56,7 +56,8 @@ class ValetSite: ValetListable {
|
||||
/// Which version of PHP is actually used to serve this site.
|
||||
var servingPhpVersion: String {
|
||||
return self.isolatedPhpVersion?.versionNumber.short
|
||||
?? PhpEnv.phpInstall.version.short
|
||||
?? PhpEnv.phpInstall?.version.short
|
||||
?? "???"
|
||||
}
|
||||
|
||||
enum VersionSource: String {
|
||||
@ -143,11 +144,16 @@ class ValetSite: ValetListable {
|
||||
return
|
||||
}
|
||||
|
||||
guard let linked = PhpEnv.phpInstall else {
|
||||
self.composerPhpCompatibleWithLinked = false
|
||||
return
|
||||
}
|
||||
|
||||
// Split the composer list (on "|") to evaluate multiple constraints
|
||||
// For example, for Laravel 8 projects the value is "^7.3|^8.0"
|
||||
self.composerPhpCompatibleWithLinked = self.composerPhp.split(separator: "|")
|
||||
.map { string in
|
||||
let origin = self.isolatedPhpVersion?.versionNumber.short ?? PhpEnv.phpInstall.version.long
|
||||
let origin = self.isolatedPhpVersion?.versionNumber.short ?? linked.version.long
|
||||
return !PhpVersionNumberCollection.make(from: [origin])
|
||||
.matching(constraint: string.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||
.isEmpty
|
||||
@ -251,7 +257,7 @@ class ValetSite: ValetListable {
|
||||
}
|
||||
|
||||
func getListablePhpVersion() -> String {
|
||||
return self.servingPhpVersion
|
||||
return self.servingPhpVersion ?? "—"
|
||||
}
|
||||
|
||||
func getListableKind() -> String {
|
||||
|
@ -207,12 +207,17 @@ extension MainMenu {
|
||||
}
|
||||
|
||||
@objc func openActiveConfigFolder() {
|
||||
if PhpEnv.phpInstall.hasErrorState {
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
// TODO: Can't open the config if no PHP version is active
|
||||
return
|
||||
}
|
||||
|
||||
if install.hasErrorState {
|
||||
Actions.openGenericPhpConfigFolder()
|
||||
return
|
||||
}
|
||||
|
||||
Actions.openPhpConfigFolder(version: PhpEnv.phpInstall.version.short)
|
||||
Actions.openPhpConfigFolder(version: install.version.short)
|
||||
}
|
||||
|
||||
@objc func openPhpMonitorConfigurationFile() {
|
||||
|
@ -12,7 +12,7 @@ import AppKit
|
||||
extension MainMenu {
|
||||
|
||||
@MainActor @objc func fixMyValet() {
|
||||
let previousVersion = PhpEnv.phpInstall.version.short
|
||||
let previousVersion = PhpEnv.phpInstall?.version.short
|
||||
|
||||
if !PhpEnv.shared.availablePhpVersions.contains(PhpEnv.brewPhpAlias) {
|
||||
presentAlertForMissingFormula()
|
||||
@ -34,10 +34,10 @@ extension MainMenu {
|
||||
Task { @MainActor in
|
||||
await Actions.fixMyValet()
|
||||
|
||||
if previousVersion == PhpEnv.brewPhpAlias {
|
||||
if previousVersion == PhpEnv.brewPhpAlias || previousVersion == nil {
|
||||
self.presentAlertForSameVersion()
|
||||
} else {
|
||||
self.presentAlertForDifferentVersion(version: previousVersion)
|
||||
self.presentAlertForDifferentVersion(version: previousVersion!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ extension MainMenu {
|
||||
// Attempt to find out if PHP-FPM is broken
|
||||
Log.info("Determining broken PHP-FPM...")
|
||||
let installation = PhpEnv.phpInstall
|
||||
installation.notifyAboutBrokenPhpFpm()
|
||||
installation?.notifyAboutBrokenPhpFpm()
|
||||
|
||||
// Check for other problems
|
||||
WarningManager.shared.evaluateWarnings()
|
||||
|
@ -118,6 +118,11 @@ extension MainMenu {
|
||||
preference: .notifyAboutVersionChange
|
||||
)
|
||||
|
||||
Task { PhpEnv.phpInstall.notifyAboutBrokenPhpFpm() }
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
Log.err("Cannot notify about version change if PHP is unlinked")
|
||||
return
|
||||
}
|
||||
|
||||
Task { install.notifyAboutBrokenPhpFpm() }
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +134,13 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
||||
} else {
|
||||
// The dynamic icon has been requested
|
||||
let long = Preferences.preferences[.fullPhpVersionDynamicIcon] as! Bool
|
||||
setStatusBarImage(version: long ? PhpEnv.phpInstall.version.long : PhpEnv.phpInstall.version.short)
|
||||
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
setStatusBarImage(version: "???")
|
||||
return
|
||||
}
|
||||
|
||||
setStatusBarImage(version: long ? install.version.long : install.version.short)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,13 @@ import Cocoa
|
||||
extension StatusMenu {
|
||||
|
||||
func addPhpVersionMenuItems() {
|
||||
if PhpEnv.phpInstall.hasErrorState {
|
||||
if PhpEnv.phpInstall == nil || 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) })
|
||||
}
|
||||
|
||||
addItem(HeaderView.asMenuItem(
|
||||
text: "\("mi_php_version".localized) \(PhpEnv.phpInstall.version.long)",
|
||||
text: "\("mi_php_version".localized) \(PhpEnv.phpInstall!.version.long)",
|
||||
minimumWidth: 280 // this ensures the menu is at least wide enough not to cause clipping
|
||||
))
|
||||
}
|
||||
@ -60,9 +60,10 @@ extension StatusMenu {
|
||||
|
||||
let action = #selector(MainMenu.switchToPhpVersion(sender:))
|
||||
let brew = (shortVersion == PhpEnv.brewPhpAlias) ? "php" : "php@\(shortVersion)"
|
||||
|
||||
let menuItem = PhpMenuItem(
|
||||
title: "\("mi_php_switch".localized) \(versionString) (\(brew))",
|
||||
action: (shortVersion == PhpEnv.phpInstall.version.short)
|
||||
action: (shortVersion == PhpEnv.phpInstall?.version.short)
|
||||
? nil
|
||||
: action, keyEquivalent: "\(shortcutKey)"
|
||||
)
|
||||
@ -145,7 +146,12 @@ extension StatusMenu {
|
||||
// MARK: - Stats
|
||||
|
||||
func addStatsMenuItem() {
|
||||
guard let stats = PhpEnv.phpInstall.limits else { return }
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
Log.info("Not showing stats menu item if no PHP version is linked.")
|
||||
return
|
||||
}
|
||||
|
||||
guard let stats = install.limits else { return }
|
||||
|
||||
addItem(StatsView.asMenuItem(
|
||||
memory: stats.memory_limit,
|
||||
@ -157,14 +163,19 @@ extension StatusMenu {
|
||||
// MARK: - Extensions
|
||||
|
||||
func addExtensionsMenuItems() {
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
Log.info("Not showing extensions menu items if no PHP version is linked.")
|
||||
return
|
||||
}
|
||||
|
||||
addItem(HeaderView.asMenuItem(text: "mi_detected_extensions".localized))
|
||||
|
||||
if PhpEnv.phpInstall.extensions.isEmpty {
|
||||
if install.extensions.isEmpty {
|
||||
addItem(NSMenuItem(title: "mi_no_extensions_detected".localized, action: nil, keyEquivalent: ""))
|
||||
}
|
||||
|
||||
var shortcutKey = 1
|
||||
for phpExtension in PhpEnv.phpInstall.extensions {
|
||||
for phpExtension in install.extensions {
|
||||
addExtensionItem(phpExtension, shortcutKey)
|
||||
shortcutKey += 1
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ class Stats {
|
||||
*/
|
||||
public static func evaluateSponsorMessageShouldBeDisplayed() {
|
||||
|
||||
if Homebrew.fake {
|
||||
return Log.info("A fake environment is in use, skipping sponsor alert.")
|
||||
if Shell is TestableShell {
|
||||
return Log.info("A fake shell is in use, skipping sponsor alert.")
|
||||
}
|
||||
|
||||
if Bundle.main.bundleIdentifier?.contains("beta") ?? false {
|
||||
@ -142,7 +142,13 @@ class Stats {
|
||||
}
|
||||
|
||||
public static func evaluateLastLinkedPhpVersion() {
|
||||
let currentVersion = PhpEnv.phpInstall.version.short
|
||||
guard let linked = PhpEnv.phpInstall else {
|
||||
// TODO: Actually notify the user that no version is linked.
|
||||
Log.info("No version is currently linked.")
|
||||
return
|
||||
}
|
||||
|
||||
let currentVersion = linked.version.short
|
||||
let previousVersion = Stats.lastGlobalPhpVersion
|
||||
|
||||
// Save the PHP version that is currently in use (only if unknown)
|
||||
|
@ -88,10 +88,14 @@ struct Preset: Codable, Equatable {
|
||||
applyConfigurationValue(key: conf.key, value: conf.value ?? "")
|
||||
}
|
||||
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
Log.info("Cannot toggle extensions if no PHP version is linked.")
|
||||
return
|
||||
}
|
||||
|
||||
// Apply the extension changes in-place afterward
|
||||
for ext in extensions {
|
||||
for foundExt in PhpEnv.phpInstall.extensions
|
||||
where foundExt.name == ext.key && foundExt.enabled != ext.value {
|
||||
for foundExt in install.extensions where foundExt.name == ext.key && foundExt.enabled != ext.value {
|
||||
Log.info("Toggling extension \(foundExt.name) in \(foundExt.file)")
|
||||
await foundExt.toggle()
|
||||
break
|
||||
@ -125,7 +129,7 @@ struct Preset: Codable, Equatable {
|
||||
// MARK: - Apply Functionality
|
||||
|
||||
private func switchToPhpVersionIfValid() async -> Bool {
|
||||
if PhpEnv.shared.currentInstall.version.short == self.version! {
|
||||
if PhpEnv.shared.currentInstall?.version.short == self.version! {
|
||||
Log.info("The version we are supposed to switch to is already active.")
|
||||
return true
|
||||
}
|
||||
@ -213,8 +217,12 @@ struct Preset: Codable, Equatable {
|
||||
return nil
|
||||
}
|
||||
|
||||
if PhpEnv.shared.currentInstall.version.short != version {
|
||||
return PhpEnv.shared.currentInstall.version.short
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if install.version.short != version {
|
||||
return install.version.short
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -226,8 +234,12 @@ struct Preset: Codable, Equatable {
|
||||
private func diffExtensions() -> [String: Bool] {
|
||||
var items: [String: Bool] = [:]
|
||||
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
fatalError("If no PHP version is linked, diffing extensions is not possible.")
|
||||
}
|
||||
|
||||
for (key, value) in self.extensions {
|
||||
for foundExt in PhpEnv.phpInstall.extensions
|
||||
for foundExt in install.extensions
|
||||
where foundExt.name == key && foundExt.enabled != value {
|
||||
// Save the original value of the extension
|
||||
items[foundExt.name] = foundExt.enabled
|
||||
|
@ -97,7 +97,7 @@ struct VersionPopoverView: View {
|
||||
if site.isolatedPhpVersion != nil {
|
||||
information += "alert.composer_php_isolated.desc".localized(
|
||||
site.isolatedPhpVersion!.versionNumber.short,
|
||||
PhpEnv.phpInstall.version.short
|
||||
PhpEnv.phpInstall?.version.short ?? "???"
|
||||
)
|
||||
information += "\n\n"
|
||||
}
|
||||
|
@ -33,7 +33,13 @@ extension App {
|
||||
return
|
||||
}
|
||||
|
||||
let url = URL(fileURLWithPath: "\(Paths.etcPath)/php/\(PhpEnv.phpInstall.version.short)")
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
Log.info("It appears as if no PHP installation is currently active.")
|
||||
Log.info("The FS watcher will be disabled until a PHP install is active.")
|
||||
return
|
||||
}
|
||||
|
||||
let url = URL(fileURLWithPath: "\(Paths.etcPath)/php/\(install.version.short)")
|
||||
|
||||
// Check whether the watcher exists and schedule on the main thread
|
||||
// if we don't consistently do this, the app will create duplicate watchers
|
||||
|
@ -525,7 +525,7 @@ If you are seeing this message but are confused why this folder has gone missing
|
||||
|
||||
// Valet version too new or old
|
||||
"startup.errors.valet_version_not_supported.title" = "This version of Valet is not supported";
|
||||
"startup.errors.valet_version_not_supported.subtitle" = "You are running a version of Valet that is currently not supported (%@). PHP Monitor currently works with Valet v2, v3 and v4. In order to avoid causing issues on your system, PHP Monitor cannot start.";
|
||||
"startup.errors.valet_version_not_supported.subtitle" = "You are running a version of Valet that is currently not supported. PHP Monitor currently works with Valet v2, v3 and v4. In order to avoid causing issues on your system, PHP Monitor cannot start.";
|
||||
"startup.errors.valet_version_not_supported.desc" = "You must install a version of Valet that is compatible with PHP Monitor, or you may need to upgrade to a newer version of PHP Monitor which may include compatibility for this version of Valet (consult the latest release notes for more info).";
|
||||
|
||||
/// Brew & sudoers
|
||||
|
Reference in New Issue
Block a user