mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-08 04:20:07 +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 */; };
|
C40B24F127A3106D0018C7D2 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E67279DE0540010F296 /* ServicesView.swift */; };
|
||||||
C40B24F227A310770018C7D2 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; };
|
C40B24F227A310770018C7D2 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; };
|
||||||
C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47331A1247093B7009A0597 /* StatusMenu.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 */; };
|
C40C7F1E2772136000DDDCDC /* PhpEnv.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F1D2772136000DDDCDC /* PhpEnv.swift */; };
|
||||||
C40C7F1F2772136000DDDCDC /* 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 */; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
C40C7F2F27722E8D00DDDCDC /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
|
||||||
@ -554,6 +557,14 @@
|
|||||||
path = Notice;
|
path = Notice;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
C40C5C9E2846A42D00E28255 /* Presets */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C40C5C9B2846A40600E28255 /* Preset.swift */,
|
||||||
|
);
|
||||||
|
path = Presets;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
C40C7F1C27720E1400DDDCDC /* Test Files */ = {
|
C40C7F1C27720E1400DDDCDC /* Test Files */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -643,6 +654,7 @@
|
|||||||
5420395726135DB800FB00FA /* Preferences */,
|
5420395726135DB800FB00FA /* Preferences */,
|
||||||
C44C198F276E3A380072762D /* Progress */,
|
C44C198F276E3A380072762D /* Progress */,
|
||||||
C4C8E81D276F5686003AC782 /* Watcher */,
|
C4C8E81D276F5686003AC782 /* Watcher */,
|
||||||
|
C40C5C9E2846A42D00E28255 /* Presets */,
|
||||||
C4EE55B027708BB2001DF387 /* SwiftUI */,
|
C4EE55B027708BB2001DF387 /* SwiftUI */,
|
||||||
);
|
);
|
||||||
path = Domain;
|
path = Domain;
|
||||||
@ -1212,6 +1224,7 @@
|
|||||||
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */,
|
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */,
|
||||||
C4B585442770FE3900DA4FBE /* Command.swift in Sources */,
|
C4B585442770FE3900DA4FBE /* Command.swift in Sources */,
|
||||||
C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */,
|
C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */,
|
||||||
|
C40C5C9C2846A40600E28255 /* Preset.swift in Sources */,
|
||||||
C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */,
|
C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */,
|
||||||
C4EE55AB27708B9E001DF387 /* Preview.swift in Sources */,
|
C4EE55AB27708B9E001DF387 /* Preview.swift in Sources */,
|
||||||
C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */,
|
C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */,
|
||||||
@ -1353,6 +1366,7 @@
|
|||||||
C41E871B2763D42300161EE0 /* DomainListVC+ContextMenu.swift in Sources */,
|
C41E871B2763D42300161EE0 /* DomainListVC+ContextMenu.swift in Sources */,
|
||||||
C40C7F3127722E8D00DDDCDC /* Logger.swift in Sources */,
|
C40C7F3127722E8D00DDDCDC /* Logger.swift in Sources */,
|
||||||
C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */,
|
C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */,
|
||||||
|
C40C5C9D2846A40600E28255 /* Preset.swift in Sources */,
|
||||||
C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */,
|
C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */,
|
||||||
C42800AB28452AA50099C999 /* StatusMenu+Items.swift in Sources */,
|
C42800AB28452AA50099C999 /* StatusMenu+Items.swift in Sources */,
|
||||||
C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */,
|
C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */,
|
||||||
|
@ -201,10 +201,48 @@ extension MainMenu {
|
|||||||
PhpEnv.switcher.performSwitch(
|
PhpEnv.switcher.performSwitch(
|
||||||
to: version,
|
to: version,
|
||||||
completion: {
|
completion: {
|
||||||
|
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
||||||
|
App.shared.handlePhpConfigWatcher()
|
||||||
PhpEnv.shared.delegate?.switcherDidCompleteSwitch(to: version)
|
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 switcherDidStartSwitching(to version: String) {}
|
||||||
|
|
||||||
func switcherDidCompleteSwitch(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
|
// Mark as no longer busy
|
||||||
PhpEnv.shared.isBusy = false
|
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()
|
let outcome = BetterAlert()
|
||||||
.withInformation(
|
.withInformation(
|
||||||
title: "alert.php_switch_failed.title".localized(version),
|
title: "alert.php_switch_failed.title".localized(version),
|
||||||
|
@ -17,79 +17,3 @@ struct CustomPrefs: Decodable {
|
|||||||
case presets = "presets"
|
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