1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-07 03:50:08 +02:00

Allow installation and removal of extensions (#266)

This commit is contained in:
2023-11-21 22:18:28 +01:00
parent f39732a0e6
commit 87c44f3ae3
15 changed files with 438 additions and 110 deletions

View File

@ -7,6 +7,19 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
0309E6672B0D4B2F002AC007 /* BrewExtensionsObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0309E6662B0D4B2F002AC007 /* BrewExtensionsObservable.swift */; };
033D45982B0D4EC600070080 /* InstallPhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45972B0D4EC600070080 /* InstallPhpExtensionCommand.swift */; };
033D45992B0D4EC600070080 /* InstallPhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45972B0D4EC600070080 /* InstallPhpExtensionCommand.swift */; };
033D459A2B0D4EC600070080 /* InstallPhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45972B0D4EC600070080 /* InstallPhpExtensionCommand.swift */; };
033D459B2B0D4EC600070080 /* InstallPhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45972B0D4EC600070080 /* InstallPhpExtensionCommand.swift */; };
033D459E2B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */; };
033D459F2B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */; };
033D45A02B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */; };
033D45A12B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */; };
033D45A32B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */; };
033D45A42B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */; };
033D45A52B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */; };
033D45A62B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */; };
03E36FE728D9219000636F7F /* ActiveShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E36FE628D9219000636F7F /* ActiveShell.swift */; }; 03E36FE728D9219000636F7F /* ActiveShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E36FE628D9219000636F7F /* ActiveShell.swift */; };
03E36FE828D9219000636F7F /* ActiveShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E36FE628D9219000636F7F /* ActiveShell.swift */; }; 03E36FE828D9219000636F7F /* ActiveShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E36FE628D9219000636F7F /* ActiveShell.swift */; };
5420395926135DC100FB00FA /* PreferencesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395826135DC100FB00FA /* PreferencesVC.swift */; }; 5420395926135DC100FB00FA /* PreferencesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395826135DC100FB00FA /* PreferencesVC.swift */; };
@ -159,10 +172,10 @@
C43A8A1A25D9CD1000591B77 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43A8A1925D9CD1000591B77 /* Utility.swift */; }; C43A8A1A25D9CD1000591B77 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43A8A1925D9CD1000591B77 /* Utility.swift */; };
C43A8A2025D9D1D700591B77 /* brew-formula.json in Resources */ = {isa = PBXBuildFile; fileRef = C43A8A1F25D9D1D700591B77 /* brew-formula.json */; }; C43A8A2025D9D1D700591B77 /* brew-formula.json in Resources */ = {isa = PBXBuildFile; fileRef = C43A8A1F25D9D1D700591B77 /* brew-formula.json */; };
C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */; }; C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */; };
C43BCD4429FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* InstallAndUpgradeCommand.swift */; }; C43BCD4429FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */; };
C43BCD4529FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* InstallAndUpgradeCommand.swift */; }; C43BCD4529FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */; };
C43BCD4629FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* InstallAndUpgradeCommand.swift */; }; C43BCD4629FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */; };
C43BCD4729FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* InstallAndUpgradeCommand.swift */; }; C43BCD4729FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */; };
C43FDBE929A932B0003D85EC /* PhpConfigChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43FDBE829A932B0003D85EC /* PhpConfigChecker.swift */; }; C43FDBE929A932B0003D85EC /* PhpConfigChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43FDBE829A932B0003D85EC /* PhpConfigChecker.swift */; };
C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F427E2582B0045BD4E /* DomainListNameCell.swift */; }; C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F427E2582B0045BD4E /* DomainListNameCell.swift */; };
C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F627E258410045BD4E /* DomainListPhpCell.swift */; }; C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F627E258410045BD4E /* DomainListPhpCell.swift */; };
@ -871,7 +884,11 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
0309E6662B0D4B2F002AC007 /* BrewExtensionsObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewExtensionsObservable.swift; sourceTree = "<group>"; };
0336CAAF2B0D0CDA009A1034 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; }; 0336CAAF2B0D0CDA009A1034 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
033D45972B0D4EC600070080 /* InstallPhpExtensionCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallPhpExtensionCommand.swift; sourceTree = "<group>"; };
033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemovePhpExtensionCommand.swift; sourceTree = "<group>"; };
033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PhpExtensionManagerView+Actions.swift"; sourceTree = "<group>"; };
03E36FE628D9219000636F7F /* ActiveShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveShell.swift; sourceTree = "<group>"; }; 03E36FE628D9219000636F7F /* ActiveShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveShell.swift; sourceTree = "<group>"; };
5420395826135DC100FB00FA /* PreferencesVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesVC.swift; sourceTree = "<group>"; }; 5420395826135DC100FB00FA /* PreferencesVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesVC.swift; sourceTree = "<group>"; };
5420395E2613607600FB00FA /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; }; 5420395E2613607600FB00FA /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
@ -964,7 +981,7 @@
C43A8A1925D9CD1000591B77 /* Utility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = "<group>"; }; C43A8A1925D9CD1000591B77 /* Utility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = "<group>"; };
C43A8A1F25D9D1D700591B77 /* brew-formula.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "brew-formula.json"; sourceTree = "<group>"; }; C43A8A1F25D9D1D700591B77 /* brew-formula.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "brew-formula.json"; sourceTree = "<group>"; };
C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewPackageTest.swift; sourceTree = "<group>"; }; C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewPackageTest.swift; sourceTree = "<group>"; };
C43BCD4329FBEF40001547BC /* InstallAndUpgradeCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallAndUpgradeCommand.swift; sourceTree = "<group>"; }; C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifyPhpVersionCommand.swift; sourceTree = "<group>"; };
C43FDBE829A932B0003D85EC /* PhpConfigChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpConfigChecker.swift; sourceTree = "<group>"; }; C43FDBE829A932B0003D85EC /* PhpConfigChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpConfigChecker.swift; sourceTree = "<group>"; };
C44067F427E2582B0045BD4E /* DomainListNameCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListNameCell.swift; sourceTree = "<group>"; }; C44067F427E2582B0045BD4E /* DomainListNameCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListNameCell.swift; sourceTree = "<group>"; };
C44067F627E258410045BD4E /* DomainListPhpCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListPhpCell.swift; sourceTree = "<group>"; }; C44067F627E258410045BD4E /* DomainListPhpCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListPhpCell.swift; sourceTree = "<group>"; };
@ -1185,6 +1202,21 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
0309E6652B0D4B1D002AC007 /* Data */ = {
isa = PBXGroup;
children = (
0309E6662B0D4B2F002AC007 /* BrewExtensionsObservable.swift */,
);
path = Data;
sourceTree = "<group>";
};
033D459C2B0D506B00070080 /* PHP Versions */ = {
isa = PBXGroup;
children = (
);
path = "PHP Versions";
sourceTree = "<group>";
};
5420395726135DB800FB00FA /* Preferences */ = { 5420395726135DB800FB00FA /* Preferences */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1430,6 +1462,7 @@
C4292D512B023F37004F0D2A /* PHP Extension Manager */ = { C4292D512B023F37004F0D2A /* PHP Extension Manager */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
0309E6652B0D4B1D002AC007 /* Data */,
C4292D522B023F52004F0D2A /* UI */, C4292D522B023F52004F0D2A /* UI */,
); );
path = "PHP Extension Manager"; path = "PHP Extension Manager";
@ -1440,6 +1473,7 @@
children = ( children = (
C4292D532B023F61004F0D2A /* PhpExtensionManagerWindowController.swift */, C4292D532B023F61004F0D2A /* PhpExtensionManagerWindowController.swift */,
C4292D552B024006004F0D2A /* PhpExtensionManagerView.swift */, C4292D552B024006004F0D2A /* PhpExtensionManagerView.swift */,
033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */,
); );
path = UI; path = UI;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1927,9 +1961,12 @@
C4B79EBA29CA38D100A483EE /* Commands */ = { C4B79EBA29CA38D100A483EE /* Commands */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
033D459C2B0D506B00070080 /* PHP Versions */,
C4B79EBB29CA38DB00A483EE /* BrewCommand.swift */, C4B79EBB29CA38DB00A483EE /* BrewCommand.swift */,
C43BCD4329FBEF40001547BC /* InstallAndUpgradeCommand.swift */, C43BCD4329FBEF40001547BC /* ModifyPhpVersionCommand.swift */,
C4B79ECA29CA475900A483EE /* RemovePhpVersionCommand.swift */, C4B79ECA29CA475900A483EE /* RemovePhpVersionCommand.swift */,
033D45972B0D4EC600070080 /* InstallPhpExtensionCommand.swift */,
033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */,
); );
path = Commands; path = Commands;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2472,6 +2509,7 @@
C45B91532956123A00F4EC78 /* FakeServicesManager.swift in Sources */, C45B91532956123A00F4EC78 /* FakeServicesManager.swift in Sources */,
C41C708D28AA7F7900E8D498 /* NoWarningsView.swift in Sources */, C41C708D28AA7F7900E8D498 /* NoWarningsView.swift in Sources */,
C4080FF627BD8C6400BF2C6B /* BetterAlert.swift in Sources */, C4080FF627BD8C6400BF2C6B /* BetterAlert.swift in Sources */,
0309E6672B0D4B2F002AC007 /* BrewExtensionsObservable.swift in Sources */,
C4E0F7ED27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */, C4E0F7ED27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */,
C4205A7E27F4D21800191A39 /* ValetProxy.swift in Sources */, C4205A7E27F4D21800191A39 /* ValetProxy.swift in Sources */,
C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
@ -2543,6 +2581,7 @@
5420395F2613607600FB00FA /* Preferences.swift in Sources */, 5420395F2613607600FB00FA /* Preferences.swift in Sources */,
C48D0C9325CC804200CC7490 /* XibLoadable.swift in Sources */, C48D0C9325CC804200CC7490 /* XibLoadable.swift in Sources */,
54FCFD2A276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */, 54FCFD2A276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */,
033D45982B0D4EC600070080 /* InstallPhpExtensionCommand.swift in Sources */,
C47699F128A2F3150060FEB8 /* Warning.swift in Sources */, C47699F128A2F3150060FEB8 /* Warning.swift in Sources */,
54D9E0B227E4F51E003B9AD9 /* HotKeysController.swift in Sources */, 54D9E0B227E4F51E003B9AD9 /* HotKeysController.swift in Sources */,
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */, C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */,
@ -2578,6 +2617,7 @@
C4B5853E2770FE3900DA4FBE /* Paths.swift in Sources */, C4B5853E2770FE3900DA4FBE /* Paths.swift in Sources */,
C41C1B4B22B019FF00E7CF16 /* ActivePhpInstallation.swift in Sources */, C41C1B4B22B019FF00E7CF16 /* ActivePhpInstallation.swift in Sources */,
C4FE011128084FC200D1DE6D /* SelectionVC.swift in Sources */, C4FE011128084FC200D1DE6D /* SelectionVC.swift in Sources */,
033D459E2B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */,
C4709CA228524B3400088BB8 /* StatsView.swift in Sources */, C4709CA228524B3400088BB8 /* StatsView.swift in Sources */,
C44CCD4027AFE2FC00CE40E5 /* AlertableError.swift in Sources */, C44CCD4027AFE2FC00CE40E5 /* AlertableError.swift in Sources */,
C4B6091D2853AB9700C95265 /* ServicesView.swift in Sources */, C4B6091D2853AB9700C95265 /* ServicesView.swift in Sources */,
@ -2590,6 +2630,7 @@
C40C7F1E2772136000DDDCDC /* PhpEnvironments.swift in Sources */, C40C7F1E2772136000DDDCDC /* PhpEnvironments.swift in Sources */,
C4B79EB629CA387F00A483EE /* BrewPhpFormulaeHandler.swift in Sources */, C4B79EB629CA387F00A483EE /* BrewPhpFormulaeHandler.swift in Sources */,
C476FF9822B0DD830098105B /* Alert.swift in Sources */, C476FF9822B0DD830098105B /* Alert.swift in Sources */,
033D45A32B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */,
C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */, C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */,
C4D5CFCA27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */, C4D5CFCA27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */,
C4D36615291160A1006BD146 /* WIP.swift in Sources */, C4D36615291160A1006BD146 /* WIP.swift in Sources */,
@ -2616,7 +2657,7 @@
C4B79ECB29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */, C4B79ECB29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
C40D725F2A018AE30054A067 /* BrewFormula+UI.swift in Sources */, C40D725F2A018AE30054A067 /* BrewFormula+UI.swift in Sources */,
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */, C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */,
C43BCD4429FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */, C43BCD4429FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */,
C4E2E84A28FC1E70003B070C /* DataExtension.swift in Sources */, C4E2E84A28FC1E70003B070C /* DataExtension.swift in Sources */,
C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */, C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */,
C42337A3281F19F000459A48 /* Xdebug.swift in Sources */, C42337A3281F19F000459A48 /* Xdebug.swift in Sources */,
@ -2654,6 +2695,7 @@
C471E83928F9BB650021E251 /* ValetSite.swift in Sources */, C471E83928F9BB650021E251 /* ValetSite.swift in Sources */,
C471E83A28F9BB650021E251 /* FakeValetSite.swift in Sources */, C471E83A28F9BB650021E251 /* FakeValetSite.swift in Sources */,
C471E83C28F9BB650021E251 /* ValetDomainScanner.swift in Sources */, C471E83C28F9BB650021E251 /* ValetDomainScanner.swift in Sources */,
033D459A2B0D4EC600070080 /* InstallPhpExtensionCommand.swift in Sources */,
C4E2E86928FC3002003B070C /* Utility.swift in Sources */, C4E2E86928FC3002003B070C /* Utility.swift in Sources */,
C471E83D28F9BB650021E251 /* FakeDomainScanner.swift in Sources */, C471E83D28F9BB650021E251 /* FakeDomainScanner.swift in Sources */,
C471E83F28F9BB650021E251 /* AppDelegate.swift in Sources */, C471E83F28F9BB650021E251 /* AppDelegate.swift in Sources */,
@ -2663,6 +2705,7 @@
C471E84228F9BB650021E251 /* AppDelegate+InterApp.swift in Sources */, C471E84228F9BB650021E251 /* AppDelegate+InterApp.swift in Sources */,
C471E84328F9BB650021E251 /* App.swift in Sources */, C471E84328F9BB650021E251 /* App.swift in Sources */,
C4E2E85E28FC282B003B070C /* TestableConfiguration.swift in Sources */, C4E2E85E28FC282B003B070C /* TestableConfiguration.swift in Sources */,
033D45A52B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */,
C45E2A7529199248005C7CFD /* InternalSwitcherTest.swift in Sources */, C45E2A7529199248005C7CFD /* InternalSwitcherTest.swift in Sources */,
C471E84428F9BB650021E251 /* App+ActivationPolicy.swift in Sources */, C471E84428F9BB650021E251 /* App+ActivationPolicy.swift in Sources */,
C471E84528F9BB650021E251 /* App+GlobalHotkey.swift in Sources */, C471E84528F9BB650021E251 /* App+GlobalHotkey.swift in Sources */,
@ -2721,6 +2764,7 @@
C471E86B28F9BB650021E251 /* PreferenceName.swift in Sources */, C471E86B28F9BB650021E251 /* PreferenceName.swift in Sources */,
C471E86C28F9BB650021E251 /* Preferences.swift in Sources */, C471E86C28F9BB650021E251 /* Preferences.swift in Sources */,
C4D3660D29113F20006BD146 /* System.swift in Sources */, C4D3660D29113F20006BD146 /* System.swift in Sources */,
033D45A02B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */,
C471E86D28F9BB650021E251 /* CustomPrefs.swift in Sources */, C471E86D28F9BB650021E251 /* CustomPrefs.swift in Sources */,
C45D654E29F52F74004C28F9 /* BrewPermissionFixer.swift in Sources */, C45D654E29F52F74004C28F9 /* BrewPermissionFixer.swift in Sources */,
C4E2E84C28FC1E70003B070C /* DataExtension.swift in Sources */, C4E2E84C28FC1E70003B070C /* DataExtension.swift in Sources */,
@ -2798,7 +2842,7 @@
C45B914B295607F400F4EC78 /* Service.swift in Sources */, C45B914B295607F400F4EC78 /* Service.swift in Sources */,
C471E7D928F9BA8F0021E251 /* TestableShell.swift in Sources */, C471E7D928F9BA8F0021E251 /* TestableShell.swift in Sources */,
C471E81428F9BAE80021E251 /* NSWindowExtension.swift in Sources */, C471E81428F9BAE80021E251 /* NSWindowExtension.swift in Sources */,
C43BCD4629FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */, C43BCD4629FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */,
C471E7D328F9BA8F0021E251 /* ActiveShell.swift in Sources */, C471E7D328F9BA8F0021E251 /* ActiveShell.swift in Sources */,
C42106682AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */, C42106682AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
C4B79EC829CA474200A483EE /* FakeCommand.swift in Sources */, C4B79EC829CA474200A483EE /* FakeCommand.swift in Sources */,
@ -2840,6 +2884,7 @@
C471E89128F9BB8F0021E251 /* Errors.swift in Sources */, C471E89128F9BB8F0021E251 /* Errors.swift in Sources */,
C4B79EC929CA474200A483EE /* FakeCommand.swift in Sources */, C4B79EC929CA474200A483EE /* FakeCommand.swift in Sources */,
C471E89228F9BB8F0021E251 /* Alert.swift in Sources */, C471E89228F9BB8F0021E251 /* Alert.swift in Sources */,
033D45A12B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */,
C471E89328F9BB8F0021E251 /* Application.swift in Sources */, C471E89328F9BB8F0021E251 /* Application.swift in Sources */,
C471E89428F9BB8F0021E251 /* LocalNotification.swift in Sources */, C471E89428F9BB8F0021E251 /* LocalNotification.swift in Sources */,
C441CC592AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */, C441CC592AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */,
@ -2994,9 +3039,10 @@
C471E82C28F9BB340021E251 /* ValetListable.swift in Sources */, C471E82C28F9BB340021E251 /* ValetListable.swift in Sources */,
C471E82828F9BB310021E251 /* BrewDiagnostics.swift in Sources */, C471E82828F9BB310021E251 /* BrewDiagnostics.swift in Sources */,
C471E81E28F9BB260021E251 /* BetterAlert.swift in Sources */, C471E81E28F9BB260021E251 /* BetterAlert.swift in Sources */,
C43BCD4729FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */, C43BCD4729FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */,
C44E985F29B23EBF0059F773 /* UpdateCheckTest.swift in Sources */, C44E985F29B23EBF0059F773 /* UpdateCheckTest.swift in Sources */,
C471E7D228F9BA630021E251 /* ActiveFileSystem.swift in Sources */, C471E7D228F9BA630021E251 /* ActiveFileSystem.swift in Sources */,
033D45A62B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */,
C471E80028F9BAD10021E251 /* Xdebug.swift in Sources */, C471E80028F9BAD10021E251 /* Xdebug.swift in Sources */,
C471E7F528F9BAC80021E251 /* PhpEnvironments.swift in Sources */, C471E7F528F9BAC80021E251 /* PhpEnvironments.swift in Sources */,
C471E7ED28F9BAC30021E251 /* Process.swift in Sources */, C471E7ED28F9BAC30021E251 /* Process.swift in Sources */,
@ -3007,6 +3053,7 @@
C471E7CA28F9BA480021E251 /* TestableFileSystem.swift in Sources */, C471E7CA28F9BA480021E251 /* TestableFileSystem.swift in Sources */,
C471E7DD28F9BAA30021E251 /* CommandProtocol.swift in Sources */, C471E7DD28F9BAA30021E251 /* CommandProtocol.swift in Sources */,
C471E7D128F9BA630021E251 /* RealFileSystem.swift in Sources */, C471E7D128F9BA630021E251 /* RealFileSystem.swift in Sources */,
033D459B2B0D4EC600070080 /* InstallPhpExtensionCommand.swift in Sources */,
C471E81D28F9BB260021E251 /* BetterAlertVC.swift in Sources */, C471E81D28F9BB260021E251 /* BetterAlertVC.swift in Sources */,
C471E82B28F9BB340021E251 /* Valet.swift in Sources */, C471E82B28F9BB340021E251 /* Valet.swift in Sources */,
C471E80328F9BAD40021E251 /* PhpConfigurationFile.swift in Sources */, C471E80328F9BAD40021E251 /* PhpConfigurationFile.swift in Sources */,
@ -3110,6 +3157,7 @@
C456A0C72AA614BD0080144F /* PhpPreference.swift in Sources */, C456A0C72AA614BD0080144F /* PhpPreference.swift in Sources */,
C42106672AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */, C42106672AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
033D45A42B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */,
C4FC21B128391F8E00D368BB /* MainMenu+Actions.swift in Sources */, C4FC21B128391F8E00D368BB /* MainMenu+Actions.swift in Sources */,
54D9E0B927E4F51E003B9AD9 /* KeyCombo.swift in Sources */, 54D9E0B927E4F51E003B9AD9 /* KeyCombo.swift in Sources */,
C4EED88A27A48778006D7272 /* InterAppHandler.swift in Sources */, C4EED88A27A48778006D7272 /* InterAppHandler.swift in Sources */,
@ -3189,6 +3237,7 @@
C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */, C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */,
C4B79EBD29CA38DB00A483EE /* BrewCommand.swift in Sources */, C4B79EBD29CA38DB00A483EE /* BrewCommand.swift in Sources */,
C485707828BF456300539B36 /* Warning.swift in Sources */, C485707828BF456300539B36 /* Warning.swift in Sources */,
033D459F2B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */,
C415938027A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */, C415938027A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */,
C40F505628ECA64E004AD45B /* TestableConfigurations.swift in Sources */, C40F505628ECA64E004AD45B /* TestableConfigurations.swift in Sources */,
C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */, C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */,
@ -3198,6 +3247,7 @@
C471E79428F9B23B0021E251 /* FileSystemProtocol.swift in Sources */, C471E79428F9B23B0021E251 /* FileSystemProtocol.swift in Sources */,
C4F30B0B278E203C00755FCE /* MainMenu+Startup.swift in Sources */, C4F30B0B278E203C00755FCE /* MainMenu+Startup.swift in Sources */,
C485707C28BF459500539B36 /* NoWarningsView.swift in Sources */, C485707C28BF459500539B36 /* NoWarningsView.swift in Sources */,
033D45992B0D4EC600070080 /* InstallPhpExtensionCommand.swift in Sources */,
C4F5FBCD28218CB8001065C5 /* Xdebug.swift in Sources */, C4F5FBCD28218CB8001065C5 /* Xdebug.swift in Sources */,
C40B24F227A310770018C7D2 /* Events.swift in Sources */, C40B24F227A310770018C7D2 /* Events.swift in Sources */,
C490E3B829BCA367006D2DE6 /* App+BrewWatch.swift in Sources */, C490E3B829BCA367006D2DE6 /* App+BrewWatch.swift in Sources */,
@ -3237,7 +3287,7 @@
C4D36602291132B7006BD146 /* ValetScanners.swift in Sources */, C4D36602291132B7006BD146 /* ValetScanners.swift in Sources */,
C40934AB298EEDA900D25014 /* CaskFileParserTest.swift in Sources */, C40934AB298EEDA900D25014 /* CaskFileParserTest.swift in Sources */,
C436B39E29F3C42500B6A64E /* PreferencesTabs.swift in Sources */, C436B39E29F3C42500B6A64E /* PreferencesTabs.swift in Sources */,
C43BCD4529FBEF40001547BC /* InstallAndUpgradeCommand.swift in Sources */, C43BCD4529FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */,
C4551657297AED18009B8466 /* ValetRcTest.swift in Sources */, C4551657297AED18009B8466 /* ValetRcTest.swift in Sources */,
C464ADAD275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */, C464ADAD275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */,
C40C7F1F2772136000DDDCDC /* PhpEnvironments.swift in Sources */, C40C7F1F2772136000DDDCDC /* PhpEnvironments.swift in Sources */,

View File

@ -18,4 +18,12 @@ class BusyStatus: ObservableObject {
self.title = title self.title = title
self.description = description self.description = description
} }
public static func notBusy() -> BusyStatus {
return BusyStatus(busy: false, title: "", description: "")
}
public static func busy() -> BusyStatus {
return BusyStatus(busy: false, title: "", description: "")
}
} }

View File

@ -8,15 +8,45 @@
import Foundation import Foundation
struct BrewPhpExtension: Hashable, Comparable {
let name: String
let phpVersion: String
let isInstalled: Bool
var formulaName: String {
return "\(name)@\(phpVersion)"
}
init(name: String, phpVersion: String) {
self.name = name
self.phpVersion = phpVersion
self.isInstalled = BrewPhpExtension.hasInstallationReceipt(
for: "\(name)@\(phpVersion)"
)
}
static func hasInstallationReceipt(for formulaName: String) -> Bool {
return FileSystem.fileExists("\(Paths.optPath)/\(formulaName)/INSTALL_RECEIPT.json")
}
static func < (lhs: BrewPhpExtension, rhs: BrewPhpExtension) -> Bool {
return lhs.name < rhs.name
}
static func == (lhs: BrewPhpExtension, rhs: BrewPhpExtension) -> Bool {
return lhs.name == rhs.name
}
}
class BrewTapFormulae { class BrewTapFormulae {
public static func from(tap: String) -> [String: Set<String>] { public static func from(tap: String) -> [String: [BrewPhpExtension]] {
let directory = "\(Paths.tapPath)/\(tap)/Formula" let directory = "\(Paths.tapPath)/\(tap)/Formula"
let files = try? FileSystem.getShallowContentsOfDirectory(directory) let files = try? FileSystem.getShallowContentsOfDirectory(directory)
var availableExtensions = [String: Set<String>]() var availableExtensions = [String: [BrewPhpExtension]]()
guard let files else { guard let files = files else {
return availableExtensions return availableExtensions
} }
@ -27,15 +57,22 @@ class BrewTapFormulae {
if let match = matches.first { if let match = matches.first {
if let phpExtensionRange = Range(match.range(at: 1), in: file), if let phpExtensionRange = Range(match.range(at: 1), in: file),
let versionRange = Range(match.range(at: 2), in: file) { let versionRange = Range(match.range(at: 2), in: file) {
let phpExtension = String(file[phpExtensionRange]) // Determine what the extension's name is
let phpExtensionName = String(file[phpExtensionRange])
// Determine what PHP version this is for
let phpVersion = String(file[versionRange]) let phpVersion = String(file[versionRange])
if var existingExtensions = availableExtensions[phpVersion] { // Create a new BrewPhpExtension object, which will determine
existingExtensions.insert(phpExtension) // whether this extension is installed or not
availableExtensions[phpVersion] = existingExtensions let phpExtension = BrewPhpExtension(
} else { name: phpExtensionName,
availableExtensions[phpVersion] = [phpExtension] phpVersion: phpVersion
} )
// Append the extension to the list
var extensions = availableExtensions[phpVersion, default: []]
extensions.append(phpExtension)
availableExtensions[phpVersion] = extensions.sorted()
} }
} }
} }

View File

@ -10,6 +10,8 @@ import Foundation
protocol BrewCommand { protocol BrewCommand {
func execute(onProgress: @escaping (BrewCommandProgress) -> Void) async throws func execute(onProgress: @escaping (BrewCommandProgress) -> Void) async throws
func getCommandTitle() -> String
} }
extension BrewCommand { extension BrewCommand {
@ -31,6 +33,44 @@ extension BrewCommand {
} }
return nil return nil
} }
internal func run(_ command: String, _ onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
var loggedMessages: [String] = []
let (process, _) = try! await Shell.attach(
command,
didReceiveOutput: { text, _ in
if !text.isEmpty {
Log.perf(text)
loggedMessages.append(text)
}
if let (number, text) = self.reportInstallationProgress(text) {
onProgress(.create(value: number, title: getCommandTitle(), description: text))
}
},
withTimeout: .minutes(15)
)
if process.terminationStatus <= 0 {
loggedMessages = []
return
} else {
throw BrewCommandError(error: "The command failed to run correctly.", log: loggedMessages)
}
}
internal func checkPhpTap(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
if !BrewDiagnostics.installedTaps.contains("shivammathur/php") {
let command = "brew tap shivammathur/php"
try await run(command, onProgress)
}
if !BrewDiagnostics.installedTaps.contains("shivammathur/extensions") {
let command = "brew tap shivammathur/extensions"
try await run(command, onProgress)
}
}
} }
struct BrewCommandProgress { struct BrewCommandProgress {

View File

@ -0,0 +1,81 @@
//
// InstallPhpExtensionCommand.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 21/11/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
class InstallPhpExtensionCommand: BrewCommand {
let installing: [BrewPhpExtension]
func getExtensionNames() -> String {
return installing.map { $0.name }.joined(separator: ", ")
}
func getCommandTitle() -> String {
return "phpman.steps.installing".localized(getExtensionNames())
}
public init(install extensions: [BrewPhpExtension]) {
self.installing = extensions
}
func execute(onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
let progressTitle = "phpman.steps.wait".localized
onProgress(.create(
value: 0.2,
title: progressTitle,
description: "phpman.steps.preparing".localized
))
// Make sure the tap is installed
try await self.checkPhpTap(onProgress)
// Make sure that the extension(s) are installed
try await self.installPackages(onProgress)
// Finally, complete all operations
await self.completedOperations(onProgress)
}
private func installPackages(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
// If no installations are needed, early exit
if self.installing.isEmpty {
return
}
let command = """
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
\(Paths.brew) install \(self.installing.map { $0.formulaName }.joined(separator: " ")) --force
"""
try await run(command, onProgress)
}
private func completedOperations(_ onProgress: @escaping (BrewCommandProgress) -> Void) async {
// Reload and restart PHP versions
onProgress(.create(value: 0.95, title: self.getCommandTitle(), description: "phpman.steps.reloading".localized))
// Check which version of PHP are now installed
await PhpEnvironments.detectPhpVersions()
// Keep track of the currently installed version
await MainMenu.shared.refreshActiveInstallation()
// Also rebuild the content of the main menu
await MainMenu.shared.rebuild()
// Let the UI know that the installation has been completed
onProgress(.create(
value: 1,
title: "phpman.steps.completed".localized,
description: "phpman.steps.success".localized
))
}
}

View File

@ -8,13 +8,16 @@
import Foundation import Foundation
class InstallAndUpgradeCommand: BrewCommand { class ModifyPhpVersionCommand: BrewCommand {
let title: String let title: String
let installing: [BrewPhpFormula] let installing: [BrewPhpFormula]
let upgrading: [BrewPhpFormula] let upgrading: [BrewPhpFormula]
let phpGuard: PhpGuard let phpGuard: PhpGuard
func getCommandTitle() -> String {
return title
}
/** /**
You can pass in which PHP versions need to be upgraded and which ones need to be installed. You can pass in which PHP versions need to be upgraded and which ones need to be installed.
The process will be executed in two steps: first upgrades, then installations. The process will be executed in two steps: first upgrades, then installations.
@ -58,18 +61,6 @@ class InstallAndUpgradeCommand: BrewCommand {
await self.completedOperations(onProgress) await self.completedOperations(onProgress)
} }
private func checkPhpTap(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
if !BrewDiagnostics.installedTaps.contains("shivammathur/php") {
let command = "brew tap shivammathur/php"
try await run(command, onProgress)
}
if !BrewDiagnostics.installedTaps.contains("shivammathur/extensions") {
let command = "brew tap shivammathur/extensions"
try await run(command, onProgress)
}
}
private func upgradePackages(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws { private func upgradePackages(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
// If no upgrades are needed, early exit // If no upgrades are needed, early exit
if self.upgrading.isEmpty { if self.upgrading.isEmpty {
@ -132,32 +123,6 @@ class InstallAndUpgradeCommand: BrewCommand {
try await run(command, onProgress) try await run(command, onProgress)
} }
private func run(_ command: String, _ onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
var loggedMessages: [String] = []
let (process, _) = try! await Shell.attach(
command,
didReceiveOutput: { text, _ in
if !text.isEmpty {
Log.perf(text)
loggedMessages.append(text)
}
if let (number, text) = self.reportInstallationProgress(text) {
onProgress(.create(value: number, title: self.title, description: text))
}
},
withTimeout: .minutes(15)
)
if process.terminationStatus <= 0 {
loggedMessages = []
return
} else {
throw BrewCommandError(error: "The command failed to run correctly.", log: loggedMessages)
}
}
private func completedOperations(_ onProgress: @escaping (BrewCommandProgress) -> Void) async { private func completedOperations(_ onProgress: @escaping (BrewCommandProgress) -> Void) async {
// Reload and restart PHP versions // Reload and restart PHP versions
onProgress(.create(value: 0.95, title: self.title, description: "Reloading PHP versions...")) onProgress(.create(value: 0.95, title: self.title, description: "Reloading PHP versions..."))
@ -183,5 +148,4 @@ class InstallAndUpgradeCommand: BrewCommand {
description: "The installation has succeeded." description: "The installation has succeeded."
)) ))
} }
} }

View File

@ -0,0 +1,60 @@
//
// RemovePhpExtensionCommand.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 21/11/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
class RemovePhpExtensionCommand: BrewCommand {
public let phpExtension: BrewPhpExtension
public init(remove formula: BrewPhpExtension) {
self.phpExtension = formula
}
func getCommandTitle() -> String {
return "phpman.steps.removing".localized(phpExtension.name)
}
func execute(onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
onProgress(.create(
value: 0.2,
title: getCommandTitle(),
description: "phpman.steps.removing".localized("`\(phpExtension.name)`...")
))
let command = """
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
\(Paths.brew) remove \(phpExtension.formulaName) --force --ignore-dependencies
"""
var loggedMessages: [String] = []
let (process, _) = try! await Shell.attach(
command,
didReceiveOutput: { text, _ in
if !text.isEmpty {
Log.perf(text)
loggedMessages.append(text)
}
},
withTimeout: .minutes(5)
)
if process.terminationStatus <= 0 {
onProgress(.create(value: 0.95, title: getCommandTitle(), description: "phpman.steps.reloading".localized))
await PhpEnvironments.detectPhpVersions()
await MainMenu.shared.refreshActiveInstallation()
onProgress(.create(value: 1, title: getCommandTitle(), description: "phpman.steps.success".localized))
} else {
throw BrewCommandError(error: "phpman.steps.failure".localized, log: loggedMessages)
}
}
}

View File

@ -21,12 +21,14 @@ class RemovePhpVersionCommand: BrewCommand {
self.phpGuard = PhpGuard() self.phpGuard = PhpGuard()
} }
func execute(onProgress: @escaping (BrewCommandProgress) -> Void) async throws { func getCommandTitle() -> String {
let progressTitle = "Removing PHP \(version)..." return "Removing PHP \(version)..."
}
func execute(onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
onProgress(.create( onProgress(.create(
value: 0.2, value: 0.2,
title: progressTitle, title: getCommandTitle(),
description: "Please wait while Homebrew removes PHP \(version)..." description: "Please wait while Homebrew removes PHP \(version)..."
)) ))
@ -56,7 +58,7 @@ class RemovePhpVersionCommand: BrewCommand {
) )
if process.terminationStatus <= 0 { if process.terminationStatus <= 0 {
onProgress(.create(value: 0.95, title: progressTitle, description: "Reloading PHP versions...")) onProgress(.create(value: 0.95, title: getCommandTitle(), description: "Reloading PHP versions..."))
await PhpEnvironments.detectPhpVersions() await PhpEnvironments.detectPhpVersions()
@ -66,7 +68,7 @@ class RemovePhpVersionCommand: BrewCommand {
await MainMenu.shared.switchToPhpVersionAndWait(version, silently: true) await MainMenu.shared.switchToPhpVersionAndWait(version, silently: true)
} }
onProgress(.create(value: 1, title: progressTitle, description: "The operation has succeeded.")) onProgress(.create(value: 1, title: getCommandTitle(), description: "The operation has succeeded."))
} else { } else {
throw BrewCommandError(error: "The command failed to run correctly.", log: loggedMessages) throw BrewCommandError(error: "The command failed to run correctly.", log: loggedMessages)
} }

View File

@ -9,6 +9,10 @@
import Foundation import Foundation
class FakeCommand: BrewCommand { class FakeCommand: BrewCommand {
func getCommandTitle() -> String {
return "Hello"
}
let version: String let version: String
init(version: String) { init(version: String) {

View File

@ -214,7 +214,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
@objc func openPhpVersionManager() { @objc func openPhpVersionManager() {
PhpVersionManagerWindowController.show() PhpVersionManagerWindowController.show()
} }
@objc func openPhpExtensionManager() { @objc func openPhpExtensionManager() {
PhpExtensionManagerWindowController.show() PhpExtensionManagerWindowController.show()
} }

View File

@ -0,0 +1,21 @@
//
// BrewExtensionsObservable.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 21/11/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
class BrewExtensionsObservable: ObservableObject {
@Published var extensions: [BrewPhpExtension] = []
public func loadExtensionData(for version: String) {
let tapFormulae = BrewTapFormulae.from(tap: "shivammathur/homebrew-extensions")
if let filteredTapFormulae = tapFormulae[version] {
self.extensions = filteredTapFormulae
}
}
}

View File

@ -0,0 +1,66 @@
//
// PhpExtensionManagerView+Actions.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 21/11/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
import Cocoa
extension PhpExtensionManagerView {
public func presentErrorAlert(
title: String,
description: String,
button: String,
style: NSAlert.Style = .critical
) {
Alert.confirm(
onWindow: App.shared.phpExtensionManagerWindowController!.window!,
messageText: title,
informativeText: description,
buttonTitle: button,
secondButtonTitle: "",
style: style,
onFirstButtonPressed: {}
)
}
public func runCommand(_ command: BrewCommand) async {
if PhpEnvironments.shared.isBusy {
self.presentErrorAlert(
title: "phpman.action_prevented_busy.title".localized,
description: "phpman.action_prevented_busy.desc".localized,
button: "generic.ok".localized
)
return
}
do {
self.status.busy = true
try await command.execute { progress in
Task { @MainActor in
self.status.title = progress.title
self.status.description = progress.description
self.status.busy = progress.value != 1
}
}
// TODO: Reload extensions
self.manager.loadExtensionData(for: self.phpVersion)
self.status.busy = false
} catch let error {
let error = error as! BrewCommandError
let messages = error.log.suffix(2).joined(separator: "\n")
self.status.busy = false
self.presentErrorAlert(
title: "phpman.failures.install.title".localized,
description: "phpman.failures.install.desc".localized(messages),
button: "generic.ok".localized
)
}
}
}

View File

@ -9,45 +9,25 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
class BrewExtensionsObservable: ObservableObject {
@Published var extensions: [BrewPhpExtension] = [] {
didSet {
print(self.extensions)
}
}
public func loadExtensionData(for version: String) {
let tapFormulae = BrewTapFormulae.from(tap: "shivammathur/homebrew-extensions")
if let filteredTapFormulae = tapFormulae[version] {
self.extensions = filteredTapFormulae.sorted().map({ name in
return BrewPhpExtension(name: name, isInstalled: false)
})
}
}
}
// Temp model for UI purposes
struct BrewPhpExtension {
let name: String
let isInstalled: Bool
}
struct PhpExtensionManagerView: View { struct PhpExtensionManagerView: View {
init() {
self.searchText = ""
self.phpVersion = PhpEnvironments.shared.currentInstall!.version.short
self.manager.loadExtensionData(for: self.phpVersion)
}
@ObservedObject var manager = BrewExtensionsObservable() @ObservedObject var manager = BrewExtensionsObservable()
@ObservedObject var status: BusyStatus
@State var searchText: String @State var searchText: String
@State var phpVersion: String { @State var phpVersion: String {
didSet { didSet {
self.manager.loadExtensionData(for: self.phpVersion) self.manager.loadExtensionData(for: self.phpVersion)
print(self.manager.extensions)
} }
} }
init() {
self.searchText = ""
self.status = BusyStatus.busy()
self.phpVersion = PhpEnvironments.shared.currentInstall!.version.short
self.manager.loadExtensionData(for: self.phpVersion)
self.status.busy = false
#warning("PHP extension manager does not react to PHP version changes!")
}
var filteredExtensions: [BrewPhpExtension] { var filteredExtensions: [BrewPhpExtension] {
guard !searchText.isEmpty else { guard !searchText.isEmpty else {
return manager.extensions return manager.extensions
@ -59,14 +39,20 @@ struct PhpExtensionManagerView: View {
VStack { VStack {
header.padding(20) header.padding(20)
List(Array(self.filteredExtensions.enumerated()), id: \.1.name) { (_, pExtension) in BlockingOverlayView(
listContent(for: pExtension) busy: self.status.busy,
.padding(.vertical, 8) title: self.status.title,
.padding(.horizontal, 8) text: self.status.description
) {
List(Array(self.filteredExtensions.enumerated()), id: \.1.name) { (_, pExtension) in
listContent(for: pExtension)
.padding(.vertical, 8)
.padding(.horizontal, 8)
}
.edgesIgnoringSafeArea(.top)
.listStyle(PlainListStyle())
.searchable(text: $searchText)
} }
.edgesIgnoringSafeArea(.top)
.listStyle(PlainListStyle())
.searchable(text: $searchText)
}.frame(width: 600, height: 600) }.frame(width: 600, height: 600)
} }
@ -107,11 +93,11 @@ struct PhpExtensionManagerView: View {
HStack { HStack {
if bExtension.isInstalled { if bExtension.isInstalled {
Button("phpman.buttons.uninstall".localizedForSwiftUI, role: .destructive) { Button("phpman.buttons.uninstall".localizedForSwiftUI, role: .destructive) {
Task { await self.runCommand(RemovePhpExtensionCommand(remove: bExtension)) }
} }
} else { } else {
Button("phpman.buttons.install".localizedForSwiftUI) { Button("phpman.buttons.install".localizedForSwiftUI) {
Task { await self.runCommand(InstallPhpExtensionCommand(install: [bExtension])) }
} }
} }
} }

View File

@ -10,7 +10,7 @@ import Foundation
import SwiftUI import SwiftUI
extension PhpVersionManagerView { extension PhpVersionManagerView {
public func runCommand(_ command: InstallAndUpgradeCommand) async { public func runCommand(_ command: ModifyPhpVersionCommand) async {
if PhpEnvironments.shared.isBusy { if PhpEnvironments.shared.isBusy {
self.presentErrorAlert( self.presentErrorAlert(
title: "phpman.action_prevented_busy.title".localized, title: "phpman.action_prevented_busy.title".localized,
@ -54,7 +54,7 @@ extension PhpVersionManagerView {
} }
public func repairAll() async { public func repairAll() async {
await self.runCommand(InstallAndUpgradeCommand( await self.runCommand(ModifyPhpVersionCommand(
title: "phpman.operations.repairing".localized, title: "phpman.operations.repairing".localized,
upgrading: [], upgrading: [],
installing: [] installing: []
@ -62,7 +62,7 @@ extension PhpVersionManagerView {
} }
public func upgradeAll(_ formulae: [BrewPhpFormula]) async { public func upgradeAll(_ formulae: [BrewPhpFormula]) async {
await self.runCommand(InstallAndUpgradeCommand( await self.runCommand(ModifyPhpVersionCommand(
title: "phpman.operations.updating".localized, title: "phpman.operations.updating".localized,
upgrading: formulae, upgrading: formulae,
installing: [] installing: []
@ -70,7 +70,7 @@ extension PhpVersionManagerView {
} }
public func install(_ formula: BrewPhpFormula) async { public func install(_ formula: BrewPhpFormula) async {
await self.runCommand(InstallAndUpgradeCommand( await self.runCommand(ModifyPhpVersionCommand(
title: "phpman.operations.installing".localized(formula.displayName), title: "phpman.operations.installing".localized(formula.displayName),
upgrading: [], upgrading: [],
installing: [formula] installing: [formula]

View File

@ -121,6 +121,15 @@
"phpman.buttons.repair" = "Repair"; "phpman.buttons.repair" = "Repair";
"phpman.version.prerelease" = "Pre-release"; "phpman.version.prerelease" = "Pre-release";
"phpman.steps.installing" = "Installing %@";
"phpman.steps.removing" = "Removing %@";
"phpman.steps.reloading" = "Reloading PHP versions...";
"phpman.steps.preparing" = "PHP Monitor is preparing Homebrew...";
"phpman.steps.wait" = "Please wait...";
"phpman.steps.completed" = "Operation completed!";
"phpman.steps.success" = "The operation has succeeded.";
"phpman.steps.failure" = "The command failed to run correctly.";
"phpman.title" = "PHP Version Manager"; "phpman.title" = "PHP Version Manager";
"phpman.description" = "**PHP Version Manager** lets you install, upgrade and delete different PHP versions via Homebrew without needing to run the commands in the terminal yourself."; "phpman.description" = "**PHP Version Manager** lets you install, upgrade and delete different PHP versions via Homebrew without needing to run the commands in the terminal yourself.";
"phpman.disclaimer" = "Please note that installing or upgrading PHP versions may cause other Homebrew packages to be upgraded as well. Most installation steps usually take some time, so please be patient while Homebrew does its job."; "phpman.disclaimer" = "Please note that installing or upgrading PHP versions may cause other Homebrew packages to be upgraded as well. Most installation steps usually take some time, so please be patient while Homebrew does its job.";