1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-07 03:50:08 +02: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:
2023-03-13 21:03:13 +01:00
parent e0b574b33d
commit 81ed154db1
6 changed files with 205 additions and 40 deletions

View File

@ -735,6 +735,10 @@
C4F780CC25D80B75000DBC97 /* ActivePhpInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4A22B019FF00E7CF16 /* ActivePhpInstallation.swift */; };
C4F780CD25D80B75000DBC97 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C476FF9722B0DD830098105B /* Alert.swift */; };
C4F780CE25D80B75000DBC97 /* LocalNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = C474B00524C0E98C00066A22 /* LocalNotification.swift */; };
C4F8764E29BFAF00006BBE26 /* PhpVersionInstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8764D29BFAF00006BBE26 /* PhpVersionInstaller.swift */; };
C4F8764F29BFAF00006BBE26 /* PhpVersionInstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8764D29BFAF00006BBE26 /* PhpVersionInstaller.swift */; };
C4F8765029BFAF00006BBE26 /* PhpVersionInstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8764D29BFAF00006BBE26 /* PhpVersionInstaller.swift */; };
C4F8765129BFAF00006BBE26 /* PhpVersionInstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8764D29BFAF00006BBE26 /* PhpVersionInstaller.swift */; };
C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8C0A322D4F12C002EFE61 /* DateExtension.swift */; };
C4FACE80288F1C0D00FC478F /* PreferencesWindowController+Hotkey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FACE7F288F1C0D00FC478F /* PreferencesWindowController+Hotkey.swift */; };
C4FACE81288F1C0D00FC478F /* PreferencesWindowController+Hotkey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FACE7F288F1C0D00FC478F /* PreferencesWindowController+Hotkey.swift */; };
@ -1005,6 +1009,7 @@
C4F7809B25D80344000DBC97 /* CommandTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandTest.swift; sourceTree = "<group>"; };
C4F780A725D80AE8000DBC97 /* php.ini */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = php.ini; sourceTree = "<group>"; };
C4F780AD25D80B37000DBC97 /* PhpExtensionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpExtensionTest.swift; sourceTree = "<group>"; };
C4F8764D29BFAF00006BBE26 /* PhpVersionInstaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpVersionInstaller.swift; sourceTree = "<group>"; };
C4F8C0A322D4F12C002EFE61 /* DateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtension.swift; sourceTree = "<group>"; };
C4F8C0A522D4FA41002EFE61 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
C4FACE7F288F1C0D00FC478F /* PreferencesWindowController+Hotkey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreferencesWindowController+Hotkey.swift"; sourceTree = "<group>"; };
@ -1081,6 +1086,7 @@
54B20EDF263AA22C00D3250E /* PHP */ = {
isa = PBXGroup;
children = (
C4F8764D29BFAF00006BBE26 /* PhpVersionInstaller.swift */,
C48D6C6E279CD29C00F26D7E /* PHP Version */,
C4D9ADC2277610E4007277F4 /* Switcher */,
C4F30B01278E169B00755FCE /* Homebrew */,
@ -2180,6 +2186,7 @@
C4205A7E27F4D21800191A39 /* ValetProxy.swift in Sources */,
C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
C4E49DE728F764050026AC4E /* ActiveCommand.swift in Sources */,
C4F8764E29BFAF00006BBE26 /* PhpVersionInstaller.swift in Sources */,
54FCFD30276C8DA4004CE748 /* HotkeyPreferenceView.swift in Sources */,
C450C8C628C919EC002A2B4B /* PreferenceName.swift in Sources */,
C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */,
@ -2456,6 +2463,7 @@
C471E80828F9BAD40021E251 /* PhpExtension.swift in Sources */,
C471E7F928F9BACB0021E251 /* PhpSwitcher.swift in Sources */,
C471E82A28F9BB330021E251 /* ValetListable.swift in Sources */,
C4F8765029BFAF00006BBE26 /* PhpVersionInstaller.swift in Sources */,
C471E82728F9BB310021E251 /* HomebrewDiagnostics.swift in Sources */,
C471E81C28F9BB250021E251 /* BetterAlert.swift in Sources */,
C471E7DB28F9BA8F0021E251 /* RealShell.swift in Sources */,
@ -2642,6 +2650,7 @@
C471E80028F9BAD10021E251 /* Xdebug.swift in Sources */,
C471E7F528F9BAC80021E251 /* PhpEnv.swift in Sources */,
C471E7ED28F9BAC30021E251 /* Process.swift in Sources */,
C4F8765129BFAF00006BBE26 /* PhpVersionInstaller.swift in Sources */,
C471E81128F9BAE80021E251 /* NSMenuItemExtension.swift in Sources */,
C471E7CC28F9BA5B0021E251 /* TestableShell.swift in Sources */,
C471E80C28F9BAE80021E251 /* NSWindowExtension.swift in Sources */,
@ -2681,6 +2690,7 @@
C485707128BF452E00539B36 /* WarningManager.swift in Sources */,
C41CA5EE2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */,
C4FACE81288F1C0D00FC478F /* PreferencesWindowController+Hotkey.swift in Sources */,
C4F8764F29BFAF00006BBE26 /* PhpVersionInstaller.swift in Sources */,
C40934A3298EEB2C00D25014 /* CaskFile.swift in Sources */,
54D9E0B727E4F51E003B9AD9 /* HotKey.swift in Sources */,
C413E43528DA3EB100AE33C7 /* TestableShellTest.swift in Sources */,

View File

@ -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()
}
}
}

View 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
}
}

View File

@ -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

View File

@ -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(

View File

@ -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()
}
}