mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-11-07 05:10:06 +01:00
🏗 WIP: Discern installation status
Depending on the installation status, PHP Monitor should be able to find out which versions of PHP can be installed and removed.
This commit is contained in:
@@ -130,36 +130,4 @@ class Actions {
|
||||
await brew("services restart \(Homebrew.Formulae.php)", sudo: Homebrew.Formulae.php.elevated)
|
||||
await brew("services restart \(Homebrew.Formulae.nginx)", sudo: Homebrew.Formulae.nginx.elevated)
|
||||
}
|
||||
|
||||
public static func installPhpVersion(version: String) async {
|
||||
let subject = ProgressViewSubject(
|
||||
title: "Installing PHP \(version)",
|
||||
description: "Please wait while Homebrew installs PHP \(version)..."
|
||||
)
|
||||
|
||||
let installables = [
|
||||
"8.2": "php",
|
||||
"8.1": "php@8.1",
|
||||
"8.0": "php@8.0",
|
||||
"7.4": "shivammathur/php/php@7.4",
|
||||
"7.3": "shivammathur/php/php@7.3",
|
||||
"7.2": "shivammathur/php/php@7.2",
|
||||
"7.1": "shivammathur/php/php@7.1",
|
||||
"7.0": "shivammathur/php/php@7.0"
|
||||
]
|
||||
|
||||
if installables.keys.contains(version) {
|
||||
let window = await ProgressWindowView.display(subject)
|
||||
let formula = installables[version]!
|
||||
if formula.contains("shivammathur") && !HomebrewDiagnostics.installedTaps.contains("shivammathur/php") {
|
||||
await Shell.quiet("brew tap shivammathur/php")
|
||||
}
|
||||
// TODO: Attempt to read the progress of this
|
||||
// Use the same way the composer progress is read
|
||||
await brew("install \(formula)", sudo: false)
|
||||
await PhpEnv.detectPhpVersions()
|
||||
await MainMenu.shared.refreshActiveInstallation()
|
||||
await window.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
165
phpmon/Common/PHP/PhpVersionInstaller.swift
Normal file
165
phpmon/Common/PHP/PhpVersionInstaller.swift
Normal file
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// PhpVersionInstaller.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 13/03/2023.
|
||||
// Copyright © 2023 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class PhpVersionInstaller {
|
||||
public static var installables = [
|
||||
"8.2": "php",
|
||||
"8.1": "php@8.1",
|
||||
"8.0": "php@8.0",
|
||||
"7.4": "shivammathur/php/php@7.4",
|
||||
"7.3": "shivammathur/php/php@7.3",
|
||||
"7.2": "shivammathur/php/php@7.2",
|
||||
"7.1": "shivammathur/php/php@7.1",
|
||||
"7.0": "shivammathur/php/php@7.0"
|
||||
]
|
||||
|
||||
public enum PhpInstallAction {
|
||||
case install
|
||||
case remove
|
||||
case purge
|
||||
}
|
||||
|
||||
// swiftlint:disable cyclomatic_complexity function_body_length
|
||||
public static func modifyPhpVersion(version: String, action: PhpInstallAction) async {
|
||||
let title = {
|
||||
switch action {
|
||||
case .install:
|
||||
return "Installing PHP \(version)"
|
||||
case .remove:
|
||||
return "Removing PHP \(version)"
|
||||
case .purge:
|
||||
return "Purging PHP \(version)"
|
||||
}
|
||||
}()
|
||||
|
||||
let description = {
|
||||
switch action {
|
||||
case .install:
|
||||
return "Please wait while Homebrew installs PHP \(version)..."
|
||||
case .remove:
|
||||
return "Please wait while Homebrew uninstalls PHP \(version)..."
|
||||
case .purge:
|
||||
return "Please wait while Homebrew purges PHP \(version)"
|
||||
}
|
||||
}()
|
||||
|
||||
let subject = ProgressViewSubject(
|
||||
title: title,
|
||||
description: description
|
||||
)
|
||||
|
||||
let installables = Self.installables
|
||||
|
||||
if installables.keys.contains(version) {
|
||||
let window = await ProgressWindowView.display(subject)
|
||||
let formula = installables[version]!
|
||||
|
||||
var command = ""
|
||||
|
||||
if action == .install {
|
||||
if formula.contains("shivammathur") && !HomebrewDiagnostics.installedTaps.contains("shivammathur/php") {
|
||||
await Shell.quiet("brew tap shivammathur/php")
|
||||
}
|
||||
}
|
||||
|
||||
if action == .purge || action == .remove {
|
||||
command = "brew remove \(formula) --force --ignore-dependencies"
|
||||
|
||||
if action == .purge {
|
||||
command += " --zap"
|
||||
}
|
||||
}
|
||||
|
||||
let (process, _) = try! await Shell.attach(
|
||||
command,
|
||||
didReceiveOutput: { text, _ in
|
||||
if action == .install {
|
||||
// Check if we can recognize any of the typical progress steps
|
||||
if let number = Self.reportInstallationProgress(text) {
|
||||
Task { @MainActor in
|
||||
subject.progress = number
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
withTimeout: .minutes(5)
|
||||
)
|
||||
|
||||
if process.terminationStatus <= 0 {
|
||||
Task { @MainActor in
|
||||
subject.progress = 100
|
||||
}
|
||||
|
||||
await PhpEnv.detectPhpVersions()
|
||||
await MainMenu.shared.refreshActiveInstallation()
|
||||
Task { @MainActor in
|
||||
subject.description = "The operation succeeded. This window will close in 5 seconds."
|
||||
}
|
||||
await window.close()
|
||||
} else {
|
||||
// Do not close the window and notify about failure
|
||||
Task { @MainActor in
|
||||
subject.description = "The operation failed."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func installPhpVersion(version: String) async {
|
||||
await self.modifyPhpVersion(version: version, action: .install)
|
||||
}
|
||||
|
||||
public static func removePhpVersion(version: String) async {
|
||||
await self.modifyPhpVersion(version: version, action: .remove)
|
||||
}
|
||||
|
||||
private static func reportInstallationProgress(_ text: String) -> Double? {
|
||||
if text.contains("Fetching") {
|
||||
return 10
|
||||
}
|
||||
if text.contains("Downloading") {
|
||||
return 25
|
||||
}
|
||||
if text.contains("Already downloaded") || text.contains("Downloaded") {
|
||||
return 50
|
||||
}
|
||||
if text.contains("Installing") {
|
||||
return 60
|
||||
}
|
||||
if text.contains("Pouring") {
|
||||
return 80
|
||||
}
|
||||
if text.contains("Summary") {
|
||||
return 100
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
Determine which action will be available in the PHP version manager.
|
||||
Some versions will be available to be removed, some to be installed.
|
||||
*/
|
||||
public static var availableActions: [(version: String, action: PhpInstallAction)] {
|
||||
var operations: [(version: String, action: PhpInstallAction)] = []
|
||||
|
||||
let installed = PhpEnv.shared.cachedPhpInstallations.keys
|
||||
|
||||
for installable in installables.keys {
|
||||
// While technically possible to uninstall the main formula (`php`)
|
||||
// this should be disabled in the UI... this data should be correct though
|
||||
operations.append((installable, installed.contains(installable) ? .remove : .install))
|
||||
}
|
||||
|
||||
operations.sort { $1.version < $0.version }
|
||||
|
||||
return operations
|
||||
}
|
||||
|
||||
}
|
||||
@@ -202,8 +202,12 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
||||
Task { await AppUpdater().checkForUpdates(userInitiated: true) }
|
||||
}
|
||||
|
||||
@objc func installPhp74() {
|
||||
Task { await Actions.installPhpVersion(version: "7.4") }
|
||||
@objc func installPhpVersion(sender: PhpMenuItem) {
|
||||
Task { await PhpVersionInstaller.installPhpVersion(version: sender.version) }
|
||||
}
|
||||
|
||||
@objc func removePhpVersion(sender: PhpMenuItem) {
|
||||
Task { await PhpVersionInstaller.removePhpVersion(version: sender.version) }
|
||||
}
|
||||
|
||||
// MARK: - Menu Delegate
|
||||
|
||||
@@ -91,6 +91,30 @@ extension StatusMenu {
|
||||
addItem(menuItem)
|
||||
}
|
||||
|
||||
// TODO: This is a fixed list...
|
||||
|
||||
addItem(NSMenuItem.separator())
|
||||
addItem(HeaderView.asMenuItem(text: "Experimental"))
|
||||
for result in PhpVersionInstaller.availableActions {
|
||||
let title = result.action == .install
|
||||
? "Install PHP \(result.version)..."
|
||||
: "Remove PHP \(result.version)..."
|
||||
|
||||
var action: Selector? = result.action == .install
|
||||
? #selector(MainMenu.installPhpVersion(sender:))
|
||||
: #selector(MainMenu.removePhpVersion(sender:))
|
||||
|
||||
if result.version == PhpEnv.brewPhpAlias {
|
||||
break
|
||||
}
|
||||
|
||||
addItem(PhpMenuItem(
|
||||
title: title,
|
||||
action: action,
|
||||
keyEquivalent: ""
|
||||
))
|
||||
}
|
||||
|
||||
if !PhpEnv.shared.incompatiblePhpVersions.isEmpty {
|
||||
addItem(NSMenuItem.separator())
|
||||
addItem(NSMenuItem(
|
||||
|
||||
@@ -65,12 +65,6 @@ class StatusMenu: NSMenu {
|
||||
|
||||
addItem(NSMenuItem.separator())
|
||||
|
||||
addItem(withTitle: "EXPERIMENTAL: Install PHP 7.4...",
|
||||
action: #selector(MainMenu.installPhp74),
|
||||
keyEquivalent: "")
|
||||
|
||||
addItem(NSMenuItem.separator())
|
||||
|
||||
addCoreMenuItems()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user