mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 12:00:09 +02:00
✨ Enable version switching in presets
* Moved Preset to dedicated file * Added async friendly PHP version switch * Added conditional PHP switch based on Preset
This commit is contained in:
@ -48,6 +48,8 @@
|
||||
C40B24F127A3106D0018C7D2 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E67279DE0540010F296 /* ServicesView.swift */; };
|
||||
C40B24F227A310770018C7D2 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; };
|
||||
C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47331A1247093B7009A0597 /* StatusMenu.swift */; };
|
||||
C40C5C9C2846A40600E28255 /* Preset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C5C9B2846A40600E28255 /* Preset.swift */; };
|
||||
C40C5C9D2846A40600E28255 /* Preset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C5C9B2846A40600E28255 /* Preset.swift */; };
|
||||
C40C7F1E2772136000DDDCDC /* PhpEnv.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F1D2772136000DDDCDC /* PhpEnv.swift */; };
|
||||
C40C7F1F2772136000DDDCDC /* PhpEnv.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F1D2772136000DDDCDC /* PhpEnv.swift */; };
|
||||
C40C7F2827721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */; };
|
||||
@ -307,6 +309,7 @@
|
||||
C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarIcons.swift; sourceTree = "<group>"; };
|
||||
C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterAlert.swift; sourceTree = "<group>"; };
|
||||
C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterAlertVC.swift; sourceTree = "<group>"; };
|
||||
C40C5C9B2846A40600E28255 /* Preset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preset.swift; sourceTree = "<group>"; };
|
||||
C40C7F1D2772136000DDDCDC /* PhpEnv.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpEnv.swift; sourceTree = "<group>"; };
|
||||
C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActivePhpInstallation+Checks.swift"; sourceTree = "<group>"; };
|
||||
C40C7F2F27722E8D00DDDCDC /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
|
||||
@ -554,6 +557,14 @@
|
||||
path = Notice;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C40C5C9E2846A42D00E28255 /* Presets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C40C5C9B2846A40600E28255 /* Preset.swift */,
|
||||
);
|
||||
path = Presets;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C40C7F1C27720E1400DDDCDC /* Test Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -643,6 +654,7 @@
|
||||
5420395726135DB800FB00FA /* Preferences */,
|
||||
C44C198F276E3A380072762D /* Progress */,
|
||||
C4C8E81D276F5686003AC782 /* Watcher */,
|
||||
C40C5C9E2846A42D00E28255 /* Presets */,
|
||||
C4EE55B027708BB2001DF387 /* SwiftUI */,
|
||||
);
|
||||
path = Domain;
|
||||
@ -1212,6 +1224,7 @@
|
||||
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */,
|
||||
C4B585442770FE3900DA4FBE /* Command.swift in Sources */,
|
||||
C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */,
|
||||
C40C5C9C2846A40600E28255 /* Preset.swift in Sources */,
|
||||
C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */,
|
||||
C4EE55AB27708B9E001DF387 /* Preview.swift in Sources */,
|
||||
C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */,
|
||||
@ -1353,6 +1366,7 @@
|
||||
C41E871B2763D42300161EE0 /* DomainListVC+ContextMenu.swift in Sources */,
|
||||
C40C7F3127722E8D00DDDCDC /* Logger.swift in Sources */,
|
||||
C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */,
|
||||
C40C5C9D2846A40600E28255 /* Preset.swift in Sources */,
|
||||
C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */,
|
||||
C42800AB28452AA50099C999 /* StatusMenu+Items.swift in Sources */,
|
||||
C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */,
|
||||
|
@ -201,10 +201,48 @@ extension MainMenu {
|
||||
PhpEnv.switcher.performSwitch(
|
||||
to: version,
|
||||
completion: {
|
||||
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
||||
App.shared.handlePhpConfigWatcher()
|
||||
PhpEnv.shared.delegate?.switcherDidCompleteSwitch(to: version)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Async
|
||||
|
||||
/**
|
||||
This async-friendly version of the switcher can be invoked elsewhere in the app:
|
||||
```
|
||||
Task {
|
||||
await MainMenu.shared.switchToPhp("8.1")
|
||||
// thing to do after the switch
|
||||
}
|
||||
```
|
||||
Since this async function uses `withCheckedContinuation`
|
||||
any code after will run only after the switcher is done.
|
||||
*/
|
||||
func switchToPhp(_ version: String) async {
|
||||
DispatchQueue.main.async { [self] in
|
||||
setBusyImage()
|
||||
PhpEnv.shared.isBusy = true
|
||||
PhpEnv.shared.delegate = self
|
||||
PhpEnv.shared.delegate?.switcherDidStartSwitching(to: version)
|
||||
}
|
||||
|
||||
return await withCheckedContinuation({ continuation in
|
||||
updatePhpVersionInStatusBar()
|
||||
rebuild()
|
||||
PhpEnv.switcher.performSwitch(
|
||||
to: version,
|
||||
completion: {
|
||||
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
||||
App.shared.handlePhpConfigWatcher()
|
||||
PhpEnv.shared.delegate?.switcherDidCompleteSwitch(to: version)
|
||||
continuation.resume()
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,12 +15,6 @@ extension MainMenu {
|
||||
func switcherDidStartSwitching(to version: String) {}
|
||||
|
||||
func switcherDidCompleteSwitch(to version: String) {
|
||||
// Update the PHP version
|
||||
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
||||
|
||||
// Ensure the config watcher gets reloaded
|
||||
App.shared.handlePhpConfigWatcher()
|
||||
|
||||
// Mark as no longer busy
|
||||
PhpEnv.shared.isBusy = false
|
||||
|
||||
@ -56,7 +50,7 @@ extension MainMenu {
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor private func suggestFixMyValet(failed version: String) {
|
||||
private func suggestFixMyValet(failed version: String) {
|
||||
let outcome = BetterAlert()
|
||||
.withInformation(
|
||||
title: "alert.php_switch_failed.title".localized(version),
|
||||
|
@ -17,79 +17,3 @@ struct CustomPrefs: Decodable {
|
||||
case presets = "presets"
|
||||
}
|
||||
}
|
||||
|
||||
struct Preset: Decodable {
|
||||
let name: String
|
||||
let version: String?
|
||||
let extensions: [String: Bool]
|
||||
let configuration: [String: String?]
|
||||
|
||||
public enum CodingKeys: String, CodingKey {
|
||||
case version = "php",
|
||||
name = "name",
|
||||
extensions = "extensions",
|
||||
configuration = "configuration"
|
||||
}
|
||||
|
||||
public func getMenuItemText() -> String {
|
||||
var info = extensions.count == 1
|
||||
? "preset.extension".localized(extensions.count)
|
||||
: "preset.extensions".localized(extensions.count)
|
||||
info += ", "
|
||||
info += configuration.count == 1
|
||||
? "preset.preference".localized(configuration.count)
|
||||
: "preset.preferences".localized(configuration.count)
|
||||
|
||||
if self.version == nil || !PhpEnv.shared.availablePhpVersions.contains(self.version!) {
|
||||
return "<span style=\"font-family: '-apple-system'; font-size: 12px;\">"
|
||||
+ "<b>\(name.stripped)</b><br/>"
|
||||
+ "<i style=\"font-size: 11px;\">"
|
||||
+ info + "</i>"
|
||||
+ "</span>"
|
||||
}
|
||||
|
||||
return "<span style=\"font-family: '-apple-system'; font-size: 12px;\">"
|
||||
+ "<b>\(name.stripped)</b><br/>"
|
||||
+ "<i style=\"font-size: 11px;\">"
|
||||
+ "Switches to PHP \(version!)<br/>"
|
||||
+ info + "</i>"
|
||||
+ "</span>"
|
||||
}
|
||||
|
||||
public func apply() {
|
||||
// Apply the PHP version if is considered a valid version
|
||||
// TODO
|
||||
|
||||
// Apply the configuration changes first
|
||||
for conf in configuration {
|
||||
applyConfigurationValue(key: conf.key, value: conf.value ?? "")
|
||||
}
|
||||
|
||||
// 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 {
|
||||
Log.info("Toggling extension \(foundExt.name) in \(foundExt.file)")
|
||||
foundExt.toggle()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Actions.restartPhpFpm()
|
||||
}
|
||||
|
||||
private func applyConfigurationValue(key: String, value: String) {
|
||||
guard let file = PhpEnv.shared.getConfigFile(forKey: key) else {
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
if file.has(key: key) {
|
||||
Log.info("Setting config value \(key) in \(file.filePath)")
|
||||
try file.replace(key: key, value: value)
|
||||
}
|
||||
} catch {
|
||||
Log.err("Setting \(key) to \(value) failed.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
116
phpmon/Domain/Presets/Preset.swift
Normal file
116
phpmon/Domain/Presets/Preset.swift
Normal file
@ -0,0 +1,116 @@
|
||||
//
|
||||
// Preset.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 31/05/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Preset: Decodable {
|
||||
let name: String
|
||||
let version: String?
|
||||
let extensions: [String: Bool]
|
||||
let configuration: [String: String?]
|
||||
|
||||
public enum CodingKeys: String, CodingKey {
|
||||
case version = "php",
|
||||
name = "name",
|
||||
extensions = "extensions",
|
||||
configuration = "configuration"
|
||||
}
|
||||
|
||||
public func getMenuItemText() -> String {
|
||||
var info = extensions.count == 1
|
||||
? "preset.extension".localized(extensions.count)
|
||||
: "preset.extensions".localized(extensions.count)
|
||||
info += ", "
|
||||
info += configuration.count == 1
|
||||
? "preset.preference".localized(configuration.count)
|
||||
: "preset.preferences".localized(configuration.count)
|
||||
|
||||
if self.version == nil {
|
||||
return "<span style=\"font-family: '-apple-system'; font-size: 12px;\">"
|
||||
+ "<b>\(name.stripped)</b><br/>"
|
||||
+ "<i style=\"font-size: 11px;\">"
|
||||
+ info + "</i>"
|
||||
+ "</span>"
|
||||
}
|
||||
|
||||
return "<span style=\"font-family: '-apple-system'; font-size: 12px;\">"
|
||||
+ "<b>\(name.stripped)</b><br/>"
|
||||
+ "<i style=\"font-size: 11px;\">"
|
||||
+ "Switches to PHP \(version!)<br/>"
|
||||
+ info + "</i>"
|
||||
+ "</span>"
|
||||
}
|
||||
|
||||
public func apply() {
|
||||
Task {
|
||||
// Apply the PHP version if is considered a valid version
|
||||
if self.version != nil {
|
||||
await switchToPhpVersionIfValid()
|
||||
}
|
||||
|
||||
// Apply the configuration changes first
|
||||
for conf in configuration {
|
||||
applyConfigurationValue(key: conf.key, value: conf.value ?? "")
|
||||
}
|
||||
|
||||
// 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 {
|
||||
Log.info("Toggling extension \(foundExt.name) in \(foundExt.file)")
|
||||
foundExt.toggle()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Actions.restartPhpFpm()
|
||||
}
|
||||
}
|
||||
|
||||
private func switchToPhpVersionIfValid() async {
|
||||
if PhpEnv.shared.currentInstall.version.short == self.version! {
|
||||
Log.info("The version we are supposed to switch to is already active.")
|
||||
return
|
||||
}
|
||||
|
||||
if PhpEnv.shared.availablePhpVersions.first(where: { $0 == self.version }) != nil {
|
||||
await MainMenu.shared.switchToPhp(self.version!)
|
||||
return
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
BetterAlert()
|
||||
.withInformation(
|
||||
title: "PHP version unavailable",
|
||||
subtitle: "You have specified a PHP version (\(version!)) that is unavailable.",
|
||||
description: "Please make sure this version of PHP is installed "
|
||||
+ "and you can switch to it in the dropdown. "
|
||||
+ "Currently supported versions include: "
|
||||
+ "\(PhpEnv.shared.availablePhpVersions.joined(separator: ", "))."
|
||||
)
|
||||
.withPrimary(text: "OK")
|
||||
.show()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private func applyConfigurationValue(key: String, value: String) {
|
||||
guard let file = PhpEnv.shared.getConfigFile(forKey: key) else {
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
if file.has(key: key) {
|
||||
Log.info("Setting config value \(key) in \(file.filePath)")
|
||||
try file.replace(key: key, value: value)
|
||||
}
|
||||
} catch {
|
||||
Log.err("Setting \(key) to \(value) failed.")
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user