mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 03:50:08 +02:00
👌 Async switcher (Swift concurrency)
This commit is contained in:
@ -117,14 +117,10 @@ class Actions {
|
||||
If this does not solve the issue, the user may need to install additional
|
||||
extensions and/or run `composer global update`.
|
||||
*/
|
||||
public static func fixMyValet(completed: @escaping () -> Void) {
|
||||
InternalSwitcher().performSwitch(to: PhpEnv.brewPhpAlias, completion: {
|
||||
Task { // Restart all services asynchronously and fire callback upon completion
|
||||
await brew("services restart \(Homebrew.Formulae.dnsmasq)", sudo: Homebrew.Formulae.dnsmasq.elevated)
|
||||
await brew("services restart \(Homebrew.Formulae.php)", sudo: Homebrew.Formulae.php.elevated)
|
||||
await brew("services restart \(Homebrew.Formulae.nginx)", sudo: Homebrew.Formulae.nginx.elevated)
|
||||
completed()
|
||||
}
|
||||
})
|
||||
public static func fixMyValet() async {
|
||||
await InternalSwitcher().performSwitch(to: PhpEnv.brewPhpAlias)
|
||||
await brew("services restart \(Homebrew.Formulae.dnsmasq)", sudo: Homebrew.Formulae.dnsmasq.elevated)
|
||||
await brew("services restart \(Homebrew.Formulae.php)", sudo: Homebrew.Formulae.php.elevated)
|
||||
await brew("services restart \(Homebrew.Formulae.nginx)", sudo: Homebrew.Formulae.nginx.elevated)
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ class ActivePhpInstallation {
|
||||
do {
|
||||
try determineVersion()
|
||||
} catch {
|
||||
// TODO: Throw up an alert if the PHP version cannot be parsed
|
||||
fatalError("Could not determine or parse PHP version")
|
||||
#warning("In future versions of PHP Monitor, this should not crash")
|
||||
fatalError("Could not determine or parse PHP version; aborting")
|
||||
}
|
||||
|
||||
// Initialize the list of ini files that are loaded
|
||||
|
@ -88,7 +88,7 @@ class PhpExtension {
|
||||
|
||||
if !isRunningTests {
|
||||
// When running unit tests, the MainMenu will not be available
|
||||
// TODO: Fix this dependency issue, set up a notification mechanism
|
||||
// TODO: Investigate an alternate approach w/ notification or publishable
|
||||
Task { @MainActor in
|
||||
MainMenu.shared.rebuild()
|
||||
}
|
||||
|
@ -15,45 +15,43 @@ class InternalSwitcher: PhpSwitcher {
|
||||
- unlinking the current version
|
||||
- stopping the active services
|
||||
- linking the new desired version
|
||||
|
||||
|
||||
Please note that depending on which version is installed,
|
||||
the version that is switched to may or may not be identical to `php`
|
||||
(without @version).
|
||||
|
||||
TODO: Use `async` and use structured concurrency: https://www.hackingwithswift.com/swift/5.5/structured-concurrency
|
||||
*/
|
||||
func performSwitch(to version: String, completion: @escaping () -> Void) {
|
||||
func performSwitch(to version: String) async {
|
||||
Log.info("Switching to \(version), unlinking all versions...")
|
||||
|
||||
let versions = getVersionsToBeHandled(version)
|
||||
let group = DispatchGroup()
|
||||
|
||||
PhpEnv.shared.availablePhpVersions.forEach { (available) in
|
||||
group.enter()
|
||||
|
||||
Task {
|
||||
await self.disableDefaultPhpFpmPool(available)
|
||||
await self.stopPhpVersion(available)
|
||||
group.leave()
|
||||
}
|
||||
}
|
||||
|
||||
group.notify(queue: .global(qos: .userInitiated)) {
|
||||
Task {
|
||||
Log.info("All versions have been unlinked!")
|
||||
Log.info("Linking the new version!")
|
||||
|
||||
for formula in versions {
|
||||
await self.startPhpVersion(formula, primary: (version == formula))
|
||||
await withTaskGroup(of: String.self, body: { group in
|
||||
for available in PhpEnv.shared.availablePhpVersions {
|
||||
group.addTask {
|
||||
await self.disableDefaultPhpFpmPool(available)
|
||||
await self.stopPhpVersion(available)
|
||||
return available
|
||||
}
|
||||
|
||||
Log.info("Restarting nginx, just to be sure!")
|
||||
await brew("services restart nginx", sudo: true)
|
||||
|
||||
Log.info("The new version(s) have been linked!")
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
var unlinked: [String] = []
|
||||
for await version in group {
|
||||
unlinked.append(version)
|
||||
}
|
||||
|
||||
Log.info("These versions have been unlinked: \(unlinked)")
|
||||
Log.info("Linking the new version \(version)!")
|
||||
|
||||
for formula in versions {
|
||||
Log.info("Will start PHP \(version)... (primary: \(version == formula))")
|
||||
await self.startPhpVersion(formula, primary: (version == formula))
|
||||
}
|
||||
|
||||
Log.info("Restarting nginx, just to be sure!")
|
||||
await brew("services restart nginx", sudo: true)
|
||||
|
||||
Log.info("The new version(s) have been linked!")
|
||||
})
|
||||
}
|
||||
|
||||
func getVersionsToBeHandled(_ primary: String) -> Set<String> {
|
||||
|
@ -18,6 +18,6 @@ protocol PhpSwitcherDelegate: AnyObject {
|
||||
|
||||
protocol PhpSwitcher {
|
||||
|
||||
func performSwitch(to version: String, completion: @escaping () -> Void)
|
||||
func performSwitch(to version: String) async
|
||||
|
||||
}
|
||||
|
@ -29,7 +29,9 @@ class FakeServicesManager: ServicesManager {
|
||||
self.services = []
|
||||
self.reapplyServices()
|
||||
|
||||
self.firstRunComplete = true
|
||||
Task { @MainActor in
|
||||
self.firstRunComplete = true
|
||||
}
|
||||
}
|
||||
|
||||
private func reapplyServices() {
|
||||
|
@ -15,7 +15,7 @@ class ServicesManager: ObservableObject {
|
||||
|
||||
@Published var services = [Service]()
|
||||
|
||||
@Published var firstRunComplete: Bool = false
|
||||
@Published @MainActor var firstRunComplete: Bool = false
|
||||
|
||||
public static func useFake() {
|
||||
ServicesManager.shared = FakeServicesManager.init(
|
||||
|
@ -15,7 +15,10 @@ class ValetServicesManager: ServicesManager {
|
||||
// Load the initial services state
|
||||
Task {
|
||||
await self.reloadServicesStatus()
|
||||
firstRunComplete = true
|
||||
|
||||
Task { @MainActor in
|
||||
firstRunComplete = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,17 +142,14 @@ class Valet {
|
||||
in use. This allows PHP Monitor to do different things when Valet 3.0 is enabled.
|
||||
*/
|
||||
public func evaluateFeatureSupport() {
|
||||
let isVersion2 = version.isSameMajorVersionAs(try! VersionNumber.parse("2.0"))
|
||||
let isVersion3 = version.isSameMajorVersionAs(try! VersionNumber.parse("3.0"))
|
||||
let isVersion4 = version.isSameMajorVersionAs(try! VersionNumber.parse("4.0"))
|
||||
|
||||
if isVersion2 {
|
||||
switch version.major {
|
||||
case 2:
|
||||
Log.info("You are running Valet v2. Support for site isolation is disabled.")
|
||||
} else if isVersion3 || isVersion4 {
|
||||
Log.info("You are running Valet v3 or v4. Support for site isolation is available.")
|
||||
case 3, 4:
|
||||
Log.info("You are running Valet v\(version.major). Support for site isolation is available.")
|
||||
self.features.append(.isolatedSites)
|
||||
} else {
|
||||
// TODO: Show an alert and notify that some features might not work
|
||||
default:
|
||||
#warning("An alert should be presented here")
|
||||
Log.err("This version of Valet is not supported.")
|
||||
}
|
||||
}
|
||||
|
@ -240,14 +240,11 @@ extension MainMenu {
|
||||
Task(priority: .userInitiated) { [unowned self] in
|
||||
updatePhpVersionInStatusBar()
|
||||
rebuild()
|
||||
PhpEnv.switcher.performSwitch(
|
||||
to: version,
|
||||
completion: {
|
||||
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
||||
App.shared.handlePhpConfigWatcher()
|
||||
PhpEnv.shared.delegate?.switcherDidCompleteSwitch(to: version)
|
||||
}
|
||||
)
|
||||
await PhpEnv.switcher.performSwitch(to: version)
|
||||
|
||||
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
||||
App.shared.handlePhpConfigWatcher()
|
||||
PhpEnv.shared.delegate?.switcherDidCompleteSwitch(to: version)
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,8 +256,6 @@ extension MainMenu {
|
||||
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 {
|
||||
Task { @MainActor [self] in
|
||||
@ -270,19 +265,13 @@ extension MainMenu {
|
||||
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()
|
||||
}
|
||||
)
|
||||
})
|
||||
updatePhpVersionInStatusBar()
|
||||
rebuild()
|
||||
await PhpEnv.switcher.performSwitch(to: version)
|
||||
|
||||
PhpEnv.shared.currentInstall = ActivePhpInstallation()
|
||||
App.shared.handlePhpConfigWatcher()
|
||||
PhpEnv.shared.delegate?.switcherDidCompleteSwitch(to: version)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,13 +31,13 @@ extension MainMenu {
|
||||
return
|
||||
}
|
||||
|
||||
Actions.fixMyValet {
|
||||
Task { @MainActor in
|
||||
if previousVersion == PhpEnv.brewPhpAlias {
|
||||
self.presentAlertForSameVersion()
|
||||
} else {
|
||||
self.presentAlertForDifferentVersion(version: previousVersion)
|
||||
}
|
||||
Task { @MainActor in
|
||||
await Actions.fixMyValet()
|
||||
|
||||
if previousVersion == PhpEnv.brewPhpAlias {
|
||||
self.presentAlertForSameVersion()
|
||||
} else {
|
||||
self.presentAlertForDifferentVersion(version: previousVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +137,9 @@ struct ServiceView: View {
|
||||
? Color("IconColorGreen")
|
||||
: Color("IconColorRed")
|
||||
)
|
||||
}.frame(width: 25, height: 25)
|
||||
}
|
||||
.focusable(false)
|
||||
.frame(width: 25, height: 25)
|
||||
}
|
||||
}
|
||||
}.frame(minWidth: 70)
|
||||
|
Reference in New Issue
Block a user