🚀 Version 25.08
@@ -21,6 +21,25 @@
|
||||
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 */; };
|
||||
036C39022E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
||||
036C39032E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
||||
036C39042E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
||||
036C39052E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
|
||||
036C39082E5C88A7008DAEDF /* PackagistTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39072E5C88A2008DAEDF /* PackagistTest.swift */; };
|
||||
036C390A2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */; };
|
||||
036C390B2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */; };
|
||||
036C390C2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */; };
|
||||
036C390D2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */; };
|
||||
036C390F2E5C8D42008DAEDF /* PackagistError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C390E2E5C8D3B008DAEDF /* PackagistError.swift */; };
|
||||
036C39102E5C8D42008DAEDF /* PackagistError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C390E2E5C8D3B008DAEDF /* PackagistError.swift */; };
|
||||
036C39112E5C8D42008DAEDF /* PackagistError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C390E2E5C8D3B008DAEDF /* PackagistError.swift */; };
|
||||
036C39122E5C8D42008DAEDF /* PackagistError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C390E2E5C8D3B008DAEDF /* PackagistError.swift */; };
|
||||
036C39142E5CB822008DAEDF /* TestBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39132E5CB820008DAEDF /* TestBundle.swift */; };
|
||||
036C3A212E5CBBAA008DAEDF /* ValetConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F76275447F100D44ED0 /* ValetConfigurationTest.swift */; };
|
||||
039E1D792E5F0F300072D13D /* ValetUpgrader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039E1D782E5F0F2C0072D13D /* ValetUpgrader.swift */; };
|
||||
039E1D7A2E5F0F300072D13D /* ValetUpgrader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039E1D782E5F0F2C0072D13D /* ValetUpgrader.swift */; };
|
||||
039E1D7B2E5F0F300072D13D /* ValetUpgrader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039E1D782E5F0F2C0072D13D /* ValetUpgrader.swift */; };
|
||||
039E1D7C2E5F0F300072D13D /* ValetUpgrader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039E1D782E5F0F2C0072D13D /* ValetUpgrader.swift */; };
|
||||
03BFF5272E312C3D007F96FA /* Startup+Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF5262E312C39007F96FA /* Startup+Timers.swift */; };
|
||||
03BFF5282E312C3D007F96FA /* Startup+Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF5262E312C39007F96FA /* Startup+Timers.swift */; };
|
||||
03BFF5292E312C3D007F96FA /* Startup+Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF5262E312C39007F96FA /* Startup+Timers.swift */; };
|
||||
@@ -29,6 +48,14 @@
|
||||
03BFF52D2E313244007F96FA /* StatusMenu+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF52B2E313240007F96FA /* StatusMenu+Driver.swift */; };
|
||||
03BFF52E2E313244007F96FA /* StatusMenu+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF52B2E313240007F96FA /* StatusMenu+Driver.swift */; };
|
||||
03BFF52F2E313244007F96FA /* StatusMenu+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF52B2E313240007F96FA /* StatusMenu+Driver.swift */; };
|
||||
03CC1FE52E3D22120050FC18 /* InstallHomebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CC1FE42E3D220F0050FC18 /* InstallHomebrew.swift */; };
|
||||
03CC1FE62E3D22120050FC18 /* InstallHomebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CC1FE42E3D220F0050FC18 /* InstallHomebrew.swift */; };
|
||||
03CC1FE72E3D22120050FC18 /* InstallHomebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CC1FE42E3D220F0050FC18 /* InstallHomebrew.swift */; };
|
||||
03CC1FE82E3D22120050FC18 /* InstallHomebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CC1FE42E3D220F0050FC18 /* InstallHomebrew.swift */; };
|
||||
03CC1FF42E3D23130050FC18 /* ZshRunCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CC1FF32E3D230B0050FC18 /* ZshRunCommand.swift */; };
|
||||
03CC1FF52E3D23130050FC18 /* ZshRunCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CC1FF32E3D230B0050FC18 /* ZshRunCommand.swift */; };
|
||||
03CC1FF62E3D23130050FC18 /* ZshRunCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CC1FF32E3D230B0050FC18 /* ZshRunCommand.swift */; };
|
||||
03CC1FF72E3D23130050FC18 /* ZshRunCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03CC1FF32E3D230B0050FC18 /* ZshRunCommand.swift */; };
|
||||
03E36FE728D9219000636F7F /* 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 */; };
|
||||
@@ -670,7 +697,6 @@
|
||||
C4AD38B228ECD9D300FA8D83 /* TestableFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AD38B128ECD9D300FA8D83 /* TestableFileSystem.swift */; };
|
||||
C4AD38B328ECD9D300FA8D83 /* TestableFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AD38B128ECD9D300FA8D83 /* TestableFileSystem.swift */; };
|
||||
C4AF9F72275445FF00D44ED0 /* valet-config.json in Resources */ = {isa = PBXBuildFile; fileRef = C4AF9F70275445FF00D44ED0 /* valet-config.json */; };
|
||||
C4AF9F78275447F100D44ED0 /* ValetConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F76275447F100D44ED0 /* ValetConfigurationTest.swift */; };
|
||||
C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F792754499000D44ED0 /* Valet.swift */; };
|
||||
C4AF9F7B2754499000D44ED0 /* Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F792754499000D44ED0 /* Valet.swift */; };
|
||||
C4AF9F7D275454A900D44ED0 /* ValetVersionExtractorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F7C275454A900D44ED0 /* ValetVersionExtractorTest.swift */; };
|
||||
@@ -928,8 +954,16 @@
|
||||
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>"; };
|
||||
036C39012E5C883A008DAEDF /* Packagist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Packagist.swift; sourceTree = "<group>"; };
|
||||
036C39072E5C88A2008DAEDF /* PackagistTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistTest.swift; sourceTree = "<group>"; };
|
||||
036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistP2Response.swift; sourceTree = "<group>"; };
|
||||
036C390E2E5C8D3B008DAEDF /* PackagistError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistError.swift; sourceTree = "<group>"; };
|
||||
036C39132E5CB820008DAEDF /* TestBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestBundle.swift; sourceTree = "<group>"; };
|
||||
039E1D782E5F0F2C0072D13D /* ValetUpgrader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetUpgrader.swift; sourceTree = "<group>"; };
|
||||
03BFF5262E312C39007F96FA /* Startup+Timers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Startup+Timers.swift"; sourceTree = "<group>"; };
|
||||
03BFF52B2E313240007F96FA /* StatusMenu+Driver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusMenu+Driver.swift"; sourceTree = "<group>"; };
|
||||
03CC1FE42E3D220F0050FC18 /* InstallHomebrew.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallHomebrew.swift; sourceTree = "<group>"; };
|
||||
03CC1FF32E3D230B0050FC18 /* ZshRunCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZshRunCommand.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>"; };
|
||||
5420395E2613607600FB00FA /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
|
||||
@@ -1265,6 +1299,52 @@
|
||||
path = "PHP Versions";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
036C38FB2E5C8827008DAEDF /* Packagist */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
039E1D782E5F0F2C0072D13D /* ValetUpgrader.swift */,
|
||||
036C39012E5C883A008DAEDF /* Packagist.swift */,
|
||||
036C390E2E5C8D3B008DAEDF /* PackagistError.swift */,
|
||||
036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */,
|
||||
);
|
||||
path = Packagist;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
036C39062E5C8890008DAEDF /* Integration */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
036C39072E5C88A2008DAEDF /* PackagistTest.swift */,
|
||||
);
|
||||
path = Integration;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
036C3A222E5CBC33008DAEDF /* _ST */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4C1019927C65A4D001FACC2 /* Commands */,
|
||||
036C3A232E5CBC57008DAEDF /* Parsers */,
|
||||
036C39062E5C8890008DAEDF /* Integration */,
|
||||
);
|
||||
path = _ST;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
036C3A232E5CBC57008DAEDF /* Parsers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4AF9F76275447F100D44ED0 /* ValetConfigurationTest.swift */,
|
||||
);
|
||||
path = Parsers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
03BFF1D12E3CF4F2004C56A9 /* Provision */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
03CC1FF32E3D230B0050FC18 /* ZshRunCommand.swift */,
|
||||
03CC1FE42E3D220F0050FC18 /* InstallHomebrew.swift */,
|
||||
);
|
||||
path = Provision;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5420395726135DB800FB00FA /* Preferences */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -1472,6 +1552,7 @@
|
||||
C41E181722CB61EB0072CF09 /* Domain */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
03BFF1D12E3CF4F2004C56A9 /* Provision */,
|
||||
C4AF9F6B275445D300D44ED0 /* Integrations */,
|
||||
C4B13B1D25C4915000548C3A /* App */,
|
||||
C4D9ADBD27761084007277F4 /* PHP */,
|
||||
@@ -1909,6 +1990,7 @@
|
||||
C4AF9F6B275445D300D44ED0 /* Integrations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
036C38FB2E5C8827008DAEDF /* Packagist */,
|
||||
C4463FD029804C13007B93D5 /* Common */,
|
||||
C4C0E8DA27F887CC002D32A9 /* Nginx */,
|
||||
C4D89BC42783C98800A02B68 /* Composer */,
|
||||
@@ -2047,7 +2129,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C456A0D02AA6175D0080144F /* Config */,
|
||||
C4AF9F76275447F100D44ED0 /* ValetConfigurationTest.swift */,
|
||||
C4F780AD25D80B37000DBC97 /* PhpExtensionTest.swift */,
|
||||
C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */,
|
||||
C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */,
|
||||
@@ -2141,6 +2222,7 @@
|
||||
children = (
|
||||
C4E2E86328FC2F1B003B070C /* XCPMApplication.swift */,
|
||||
C40F505428ECA64E004AD45B /* TestableConfigurations.swift */,
|
||||
036C39132E5CB820008DAEDF /* TestBundle.swift */,
|
||||
C43A8A1925D9CD1000591B77 /* Utility.swift */,
|
||||
);
|
||||
path = Shared;
|
||||
@@ -2198,9 +2280,9 @@
|
||||
C4F7807A25D7F84B000DBC97 /* unit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
036C3A222E5CBC33008DAEDF /* _ST */,
|
||||
C471E6D928F9AFC20021E251 /* Testables */,
|
||||
C40C7F1C27720E1400DDDCDC /* Test Files */,
|
||||
C4C1019927C65A4D001FACC2 /* Commands */,
|
||||
C4C1019827C65A1A001FACC2 /* Versions */,
|
||||
C4C1019727C65A11001FACC2 /* Parsers */,
|
||||
);
|
||||
@@ -2617,6 +2699,7 @@
|
||||
C415D3B72770F294005EF286 /* Actions.swift in Sources */,
|
||||
C4BB39392981AFC700F8E797 /* PhpVersionSource.swift in Sources */,
|
||||
C4C3643928AE4FCE00C0770E /* StatusMenu+Items.swift in Sources */,
|
||||
036C39032E5C883B008DAEDF /* Packagist.swift in Sources */,
|
||||
C4AC51FC27E27F47008528CA /* DomainListKindCell.swift in Sources */,
|
||||
C4CDA893288F1A71007CE25F /* Keys.swift in Sources */,
|
||||
C43931C529C4BD610069165B /* PhpVersionManagerView.swift in Sources */,
|
||||
@@ -2651,6 +2734,7 @@
|
||||
C47699F128A2F3150060FEB8 /* Warning.swift in Sources */,
|
||||
54D9E0B227E4F51E003B9AD9 /* HotKeysController.swift in Sources */,
|
||||
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */,
|
||||
036C39102E5C8D42008DAEDF /* PackagistError.swift in Sources */,
|
||||
C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */,
|
||||
C41CA5ED2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */,
|
||||
C412E5FC25700D5300A1FB67 /* HomebrewDecodable.swift in Sources */,
|
||||
@@ -2682,6 +2766,7 @@
|
||||
C4927F0B27B2DFC200C55AFD /* Errors.swift in Sources */,
|
||||
C4CE7F9629683B43000102CF /* PhpVersionNumberCollection.swift in Sources */,
|
||||
C4B5853E2770FE3900DA4FBE /* Paths.swift in Sources */,
|
||||
03CC1FF42E3D23130050FC18 /* ZshRunCommand.swift in Sources */,
|
||||
C41C1B4B22B019FF00E7CF16 /* ActivePhpInstallation.swift in Sources */,
|
||||
C4FE011128084FC200D1DE6D /* SelectionVC.swift in Sources */,
|
||||
033D459E2B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */,
|
||||
@@ -2698,7 +2783,9 @@
|
||||
C4B79EB629CA387F00A483EE /* BrewPhpFormulaeHandler.swift in Sources */,
|
||||
C476FF9822B0DD830098105B /* Alert.swift in Sources */,
|
||||
033D45A32B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */,
|
||||
039E1D7C2E5F0F300072D13D /* ValetUpgrader.swift in Sources */,
|
||||
C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */,
|
||||
036C390D2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */,
|
||||
C4D5CFCA27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */,
|
||||
C485707028BF452300539B36 /* PhpDoctorWindowController.swift in Sources */,
|
||||
C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */,
|
||||
@@ -2722,6 +2809,7 @@
|
||||
C42106662AFA9FF400DF3732 /* PhpVersionManagerView+Actions.swift in Sources */,
|
||||
C4B79ECB29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
|
||||
C40D725F2A018AE30054A067 /* BrewFormula+UI.swift in Sources */,
|
||||
03CC1FE62E3D22120050FC18 /* InstallHomebrew.swift in Sources */,
|
||||
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */,
|
||||
C43BCD4429FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */,
|
||||
C4E2E84A28FC1E70003B070C /* DataExtension.swift in Sources */,
|
||||
@@ -2744,15 +2832,18 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
036C39122E5C8D42008DAEDF /* PackagistError.swift in Sources */,
|
||||
C471E82D28F9BB650021E251 /* AlertableError.swift in Sources */,
|
||||
C471E82E28F9BB650021E251 /* Errors.swift in Sources */,
|
||||
C471E82F28F9BB650021E251 /* Alert.swift in Sources */,
|
||||
039E1D7A2E5F0F300072D13D /* ValetUpgrader.swift in Sources */,
|
||||
C4FD87A929AB9ABD0002D701 /* PhpConfigChecker.swift in Sources */,
|
||||
C471E83028F9BB650021E251 /* Application.swift in Sources */,
|
||||
C471E83128F9BB650021E251 /* LocalNotification.swift in Sources */,
|
||||
C4B79EB829CA387F00A483EE /* BrewPhpFormulaeHandler.swift in Sources */,
|
||||
C471E83228F9BB650021E251 /* MenuBarImageGenerator.swift in Sources */,
|
||||
C4BB393B2981AFC700F8E797 /* PhpVersionSource.swift in Sources */,
|
||||
036C39052E5C883B008DAEDF /* Packagist.swift in Sources */,
|
||||
C471E83328F9BB650021E251 /* PMWindowController.swift in Sources */,
|
||||
C471E83428F9BB650021E251 /* VersionExtractor.swift in Sources */,
|
||||
C471E83528F9BB650021E251 /* ValetProxy.swift in Sources */,
|
||||
@@ -2818,6 +2909,7 @@
|
||||
C471E86428F9BB650021E251 /* Warning.swift in Sources */,
|
||||
C40175BA2903108900763A68 /* ValetInteractor.swift in Sources */,
|
||||
C43931C729C4BD610069165B /* PhpVersionManagerView.swift in Sources */,
|
||||
036C390A2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */,
|
||||
C4463FCE29804BCB007B93D5 /* RCFile.swift in Sources */,
|
||||
C45B9150295608E300F4EC78 /* ValetServicesManager.swift in Sources */,
|
||||
C471E86528F9BB650021E251 /* WarningManager.swift in Sources */,
|
||||
@@ -2881,6 +2973,7 @@
|
||||
C46DC7A62C7B5BC900F19D17 /* Favorites.swift in Sources */,
|
||||
C471E7E728F9BAC20021E251 /* Constants.swift in Sources */,
|
||||
C471E81628F9BAE80021E251 /* DateExtension.swift in Sources */,
|
||||
03CC1FF72E3D23130050FC18 /* ZshRunCommand.swift in Sources */,
|
||||
C469E700294CF7B200A82AB2 /* FakeValetProxy.swift in Sources */,
|
||||
C471E7D728F9BA8F0021E251 /* TestableFileSystem.swift in Sources */,
|
||||
C471E81A28F9BAE80021E251 /* TimeIntervalExtension.swift in Sources */,
|
||||
@@ -2924,6 +3017,7 @@
|
||||
C471E80728F9BAD40021E251 /* PhpConfigurationFile.swift in Sources */,
|
||||
C471E7D528F9BA8F0021E251 /* TestableConfigurations.swift in Sources */,
|
||||
C436B39F29F3C42500B6A64E /* PreferencesTabs.swift in Sources */,
|
||||
03CC1FE82E3D22120050FC18 /* InstallHomebrew.swift in Sources */,
|
||||
C471E7E328F9BAC20021E251 /* Logger.swift in Sources */,
|
||||
C471E7FD28F9BACE0021E251 /* HomebrewService.swift in Sources */,
|
||||
C471E7E428F9BAC20021E251 /* Helpers.swift in Sources */,
|
||||
@@ -2960,6 +3054,7 @@
|
||||
C471E89228F9BB8F0021E251 /* Alert.swift in Sources */,
|
||||
033D45A12B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */,
|
||||
C471E89328F9BB8F0021E251 /* Application.swift in Sources */,
|
||||
036C39022E5C883B008DAEDF /* Packagist.swift in Sources */,
|
||||
C471E89428F9BB8F0021E251 /* LocalNotification.swift in Sources */,
|
||||
C441CC592AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */,
|
||||
C40934A5298EEB2C00D25014 /* CaskFile.swift in Sources */,
|
||||
@@ -3004,6 +3099,7 @@
|
||||
C471E8B628F9BB8F0021E251 /* MainMenu+Actions.swift in Sources */,
|
||||
C471E8B728F9BB8F0021E251 /* StatusMenu.swift in Sources */,
|
||||
C471E8B828F9BB8F0021E251 /* StatusMenu+Items.swift in Sources */,
|
||||
036C390C2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */,
|
||||
C471E8B928F9BB8F0021E251 /* DomainListCellProtocol.swift in Sources */,
|
||||
C471E8BA28F9BB8F0021E251 /* DomainListTLSCell.swift in Sources */,
|
||||
C43B8FD82BA9C689000C02BE /* UnavailableContentView.swift in Sources */,
|
||||
@@ -3039,6 +3135,7 @@
|
||||
C471E8CD28F9BB8F0021E251 /* PreferencesVC.swift in Sources */,
|
||||
C471E8CE28F9BB8F0021E251 /* PreferenceName.swift in Sources */,
|
||||
C471E8CF28F9BB8F0021E251 /* Preferences.swift in Sources */,
|
||||
03CC1FF62E3D23130050FC18 /* ZshRunCommand.swift in Sources */,
|
||||
C4415E902B0287E90035F520 /* BrewFormulaeObservable.swift in Sources */,
|
||||
C4E2E84D28FC1E70003B070C /* DataExtension.swift in Sources */,
|
||||
C471E8D028F9BB8F0021E251 /* CustomPrefs.swift in Sources */,
|
||||
@@ -3084,15 +3181,18 @@
|
||||
C471E8F128F9BB8F0021E251 /* KeyCombo.swift in Sources */,
|
||||
C471E8F228F9BB8F0021E251 /* ModifierFlagsExtension.swift in Sources */,
|
||||
C471E7F028F9BAC30021E251 /* Paths.swift in Sources */,
|
||||
03CC1FE72E3D22120050FC18 /* InstallHomebrew.swift in Sources */,
|
||||
C4CE7F9929683B43000102CF /* PhpVersionNumberCollection.swift in Sources */,
|
||||
C471E7FC28F9BACE0021E251 /* HomebrewDecodable.swift in Sources */,
|
||||
C471E7CF28F9BA600021E251 /* ActiveShell.swift in Sources */,
|
||||
C4BB393C2981AFC700F8E797 /* PhpVersionSource.swift in Sources */,
|
||||
C471E7F628F9BAC80021E251 /* PhpHelper.swift in Sources */,
|
||||
039E1D7B2E5F0F300072D13D /* ValetUpgrader.swift in Sources */,
|
||||
C471E7EE28F9BAC30021E251 /* Constants.swift in Sources */,
|
||||
C40934A0298EE8E900D25014 /* AppUpdater.swift in Sources */,
|
||||
C4611E5A2AEAD2E20010BE24 /* ConfigManagerWindowController.swift in Sources */,
|
||||
C471E80E28F9BAE80021E251 /* DateExtension.swift in Sources */,
|
||||
036C390F2E5C8D42008DAEDF /* PackagistError.swift in Sources */,
|
||||
C490E3BA29BCA368006D2DE6 /* App+BrewWatch.swift in Sources */,
|
||||
03BFF5272E312C3D007F96FA /* Startup+Timers.swift in Sources */,
|
||||
C471E7D028F9BA630021E251 /* FileSystemProtocol.swift in Sources */,
|
||||
@@ -3196,6 +3296,7 @@
|
||||
C485707728BF455300539B36 /* HeaderView.swift in Sources */,
|
||||
C4F780B125D80B4D000DBC97 /* PhpExtension.swift in Sources */,
|
||||
C4D5CFCB27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */,
|
||||
036C39142E5CB822008DAEDF /* TestBundle.swift in Sources */,
|
||||
C4E6840A2AF26B830023ED25 /* BrewTapFormulae.swift in Sources */,
|
||||
C4068CA827B07A1300544CD5 /* SelectPreferenceView.swift in Sources */,
|
||||
C4F780CE25D80B75000DBC97 /* LocalNotification.swift in Sources */,
|
||||
@@ -3275,12 +3376,13 @@
|
||||
C40C5C9D2846A40600E28255 /* Preset.swift in Sources */,
|
||||
C4CE7F9729683B43000102CF /* PhpVersionNumberCollection.swift in Sources */,
|
||||
C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */,
|
||||
036C39082E5C88A7008DAEDF /* PackagistTest.swift in Sources */,
|
||||
C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */,
|
||||
C415D3E92770F692005EF286 /* AppDelegate+InterApp.swift in Sources */,
|
||||
C4E49DEE28F764A00026AC4E /* TestableCommand.swift in Sources */,
|
||||
C4AF9F78275447F100D44ED0 /* ValetConfigurationTest.swift in Sources */,
|
||||
C4611E612AEAD3110010BE24 /* ByteLimitView.swift in Sources */,
|
||||
C40175B92903108900763A68 /* ValetInteractor.swift in Sources */,
|
||||
039E1D792E5F0F300072D13D /* ValetUpgrader.swift in Sources */,
|
||||
C4CE3BBC27B324250086CA49 /* ComposerWindow.swift in Sources */,
|
||||
C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */,
|
||||
C417DC75277614690015E6EE /* Helpers.swift in Sources */,
|
||||
@@ -3295,10 +3397,12 @@
|
||||
C4E2E86528FC2F1B003B070C /* XCPMApplication.swift in Sources */,
|
||||
C4E49DE828F764050026AC4E /* ActiveCommand.swift in Sources */,
|
||||
C489E0BC2A220A4200323F5E /* FakeBrewFormulaeHandler.swift in Sources */,
|
||||
036C390B2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */,
|
||||
C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */,
|
||||
C4B79ECC29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
|
||||
C43B8FD62BA9C689000C02BE /* UnavailableContentView.swift in Sources */,
|
||||
C4FD87AA29AB9ABD0002D701 /* PhpConfigChecker.swift in Sources */,
|
||||
036C39112E5C8D42008DAEDF /* PackagistError.swift in Sources */,
|
||||
C485707D28BF45A200539B36 /* WarningView.swift in Sources */,
|
||||
C4F7809C25D80344000DBC97 /* CommandTest.swift in Sources */,
|
||||
C44CCD4127AFE2FC00CE40E5 /* AlertableError.swift in Sources */,
|
||||
@@ -3309,6 +3413,7 @@
|
||||
C4D36611291140BE006BD146 /* TestableFileSystemTest.swift in Sources */,
|
||||
C45B91542956123A00F4EC78 /* FakeServicesManager.swift in Sources */,
|
||||
C4611E5C2AEAD2E30010BE24 /* ConfigManagerWindowController.swift in Sources */,
|
||||
03CC1FE52E3D22120050FC18 /* InstallHomebrew.swift in Sources */,
|
||||
C4E2E84B28FC1E70003B070C /* DataExtension.swift in Sources */,
|
||||
C449B4F127EE7FC200C47E8A /* DomainListNameCell.swift in Sources */,
|
||||
C4F780BA25D80B62000DBC97 /* AppDelegate.swift in Sources */,
|
||||
@@ -3320,6 +3425,7 @@
|
||||
C4EA3C482BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */,
|
||||
C4F2E43B27530F750020E974 /* PhpInstallation.swift in Sources */,
|
||||
C4F780BD25D80B65000DBC97 /* Constants.swift in Sources */,
|
||||
036C39042E5C883B008DAEDF /* Packagist.swift in Sources */,
|
||||
C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */,
|
||||
C4B79EBD29CA38DB00A483EE /* BrewCommand.swift in Sources */,
|
||||
C485707828BF456300539B36 /* Warning.swift in Sources */,
|
||||
@@ -3343,6 +3449,7 @@
|
||||
C4C0E8E027F88AEB002D32A9 /* FakeDomainScanner.swift in Sources */,
|
||||
C4463FCD29804BCB007B93D5 /* RCFile.swift in Sources */,
|
||||
C47015052C46D7F10069AAE7 /* NVAlertExtension.swift in Sources */,
|
||||
03CC1FF52E3D23130050FC18 /* ZshRunCommand.swift in Sources */,
|
||||
C409349E298EE8E900D25014 /* AppUpdater.swift in Sources */,
|
||||
C4AF9F7D275454A900D44ED0 /* ValetVersionExtractorTest.swift in Sources */,
|
||||
C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */,
|
||||
@@ -3354,6 +3461,7 @@
|
||||
C485707628BF455100539B36 /* SectionHeaderView.swift in Sources */,
|
||||
C46EBC4828DB9644007ACC74 /* RealShell.swift in Sources */,
|
||||
C456A0CC2AA6166F0080144F /* BytePhpPreference.swift in Sources */,
|
||||
036C3A212E5CBBAA008DAEDF /* ValetConfigurationTest.swift in Sources */,
|
||||
C48DDD0E29C75C9E00D032D9 /* BlockingOverlayView.swift in Sources */,
|
||||
C4E4404727C56F4700D225E1 /* ValetSite.swift in Sources */,
|
||||
C44CCD4A27AFF3BC00CE40E5 /* MainMenu+Async.swift in Sources */,
|
||||
@@ -3466,7 +3574,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -3500,7 +3608,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -3534,7 +3642,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -3568,7 +3676,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -3634,7 +3742,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@@ -3694,7 +3802,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
@@ -3712,7 +3820,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1565;
|
||||
CURRENT_PROJECT_VERSION = 1588;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -3724,7 +3832,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 25.07;
|
||||
MARKETING_VERSION = 25.08;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
||||
PRODUCT_MODULE_NAME = PHP_Monitor;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -3742,7 +3850,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1565;
|
||||
CURRENT_PROJECT_VERSION = 1588;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG = NO;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -3754,7 +3862,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 25.07;
|
||||
MARKETING_VERSION = 25.08;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
||||
PRODUCT_MODULE_NAME = PHP_Monitor;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -3957,7 +4065,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
@@ -3975,7 +4083,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1565;
|
||||
CURRENT_PROJECT_VERSION = 1588;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG = NO;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -3987,7 +4095,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 25.07;
|
||||
MARKETING_VERSION = 25.08;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev;
|
||||
PRODUCT_MODULE_NAME = PHP_Monitor;
|
||||
PRODUCT_NAME = "$(TARGET_NAME) DEV";
|
||||
@@ -4072,7 +4180,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@@ -4091,7 +4199,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1565;
|
||||
CURRENT_PROJECT_VERSION = 1588;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -4103,7 +4211,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 25.07;
|
||||
MARKETING_VERSION = 25.08;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev;
|
||||
PRODUCT_MODULE_NAME = PHP_Monitor;
|
||||
PRODUCT_NAME = "$(TARGET_NAME) DEV";
|
||||
@@ -4188,7 +4296,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@@ -4207,7 +4315,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1565;
|
||||
CURRENT_PROJECT_VERSION = 1588;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -4219,7 +4327,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 25.07;
|
||||
MARKETING_VERSION = 25.08;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap;
|
||||
PRODUCT_MODULE_NAME = PHP_Monitor;
|
||||
PRODUCT_NAME = "$(TARGET_NAME) EAP";
|
||||
@@ -4252,7 +4360,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -4368,7 +4476,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
@@ -4386,7 +4494,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1565;
|
||||
CURRENT_PROJECT_VERSION = 1588;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG = NO;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -4398,7 +4506,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 25.07;
|
||||
MARKETING_VERSION = 25.08;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap;
|
||||
PRODUCT_MODULE_NAME = PHP_Monitor;
|
||||
PRODUCT_NAME = "$(TARGET_NAME) EAP";
|
||||
@@ -4431,7 +4539,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.4;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-updater";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
@@ -111,6 +111,11 @@
|
||||
value = ""
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "PHPMON_MARKETING_MODE"
|
||||
value = ""
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
|
||||
10
README.md
@@ -5,17 +5,19 @@
|
||||
|
||||
**PHP Monitor** (or *phpmon*) is a lightweight macOS utility app that runs on your Mac and displays the active PHP version in your status bar. It's tightly integrated with [Laravel Valet](https://github.com/laravel/valet), so <u>you need to have it set up if you want to use all of the functionality of the app</u> (consult the FAQ below with info about how to set up your environment).
|
||||
|
||||
<img src="./docs/screenshot.jpg" width="1280px" alt="phpmon screenshot (menu bar app)"/>
|
||||
<img src="./docs/screenshot@2x.jpg" width="1280px" alt="phpmon screenshot (menu bar app)"/>
|
||||
|
||||
<small><i>Screenshot: Showing the key functionality of PHP Monitor.</i></small>
|
||||
<small><i>Screenshot: Showing the key functionality of PHP Monitor. You can switch between PHP versions, manage PHP installations, install extensions, manage domains, and much more.</i></small>
|
||||
|
||||
It's super convenient to switch between different versions of PHP. You'll even get notifications (only if you choose to opt-in, of course)!
|
||||
It's super convenient to **globally switch** between different versions of PHP. This applies the selected version of PHP as the default on your system.
|
||||
|
||||
If you prefer, you can also **pick a PHP version on a per-site basis** (this uses Valet's site isolation feature) which is very helpful.
|
||||
|
||||
<img src="./docs/notification.png" width="370px" alt="phpmon screenshot (notification)"/>
|
||||
|
||||
PHP Monitor also gives you quick access to various useful functionality (like accessing configuration files, restarting services, and more).
|
||||
|
||||
You can also add new domains as links, isolate sites, manage various services, and perform First Aid to fix all kinds of common PHP link issues.
|
||||
You can also add new domains as links, isolate sites, manage various services, and perform First Aid to fix all kinds of common PHP and Homebrew issues.
|
||||
|
||||
## 🖥 System requirements
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 723 KiB |
BIN
docs/screenshot@2x.jpg
Normal file
|
After Width: | Height: | Size: 838 KiB |
BIN
docs/screenshot_og@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 790 B After Width: | Height: | Size: 782 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 648 KiB After Width: | Height: | Size: 633 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 819 B After Width: | Height: | Size: 820 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 499 KiB After Width: | Height: | Size: 485 KiB |
@@ -92,7 +92,7 @@ public struct PhpVersionNumberCollection: Equatable {
|
||||
// If a patch is provided then the minor version cannot be bumped.
|
||||
? $0.hasSameMajorAndMinorButNewerOrSamePatch(version, strict)
|
||||
// If a patch is not provided then the major version cannot be bumped.
|
||||
: $0.hasSameMajorButNewerOrSameMinor(version, strict)
|
||||
: $0.hasSameMajorButNewerOrSameMinor(version)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ public struct VersionNumber: Equatable, Hashable {
|
||||
return self.major == version.major
|
||||
}
|
||||
|
||||
internal func isSameAs(_ version: VersionNumber, _ strict: Bool) -> Bool {
|
||||
internal func isSameAs(_ version: VersionNumber, _ strict: Bool = true) -> Bool {
|
||||
return self.major == version.major
|
||||
&& self.minor == version.minor
|
||||
&& (strict ? self.patch(strict, version) == version.patch(strict) : true)
|
||||
@@ -103,7 +103,7 @@ public struct VersionNumber: Equatable, Hashable {
|
||||
return self.major == version.major && self.minor == version.minor
|
||||
}
|
||||
|
||||
internal func isNewerThan(_ version: VersionNumber, _ strict: Bool) -> Bool {
|
||||
internal func isNewerThan(_ version: VersionNumber, _ strict: Bool = true) -> Bool {
|
||||
return (
|
||||
self.major > version.major ||
|
||||
self.major == version.major && self.minor > version.minor ||
|
||||
@@ -112,7 +112,7 @@ public struct VersionNumber: Equatable, Hashable {
|
||||
)
|
||||
}
|
||||
|
||||
internal func isOlderThan(_ version: VersionNumber, _ strict: Bool) -> Bool {
|
||||
internal func isOlderThan(_ version: VersionNumber, _ strict: Bool = true) -> Bool {
|
||||
return (
|
||||
self.major < version.major ||
|
||||
self.major == version.major && self.minor < version.minor ||
|
||||
@@ -121,7 +121,7 @@ public struct VersionNumber: Equatable, Hashable {
|
||||
)
|
||||
}
|
||||
|
||||
internal func hasNewerMinorVersionOrPatch(_ version: VersionNumber, _ strict: Bool) -> Bool {
|
||||
internal func hasNewerMinorVersionOrPatch(_ version: VersionNumber, _ strict: Bool = true) -> Bool {
|
||||
return self.major == version.major &&
|
||||
(
|
||||
(self.minor == version.minor && self.patch(strict) >= version.patch(strict, self))
|
||||
@@ -129,12 +129,12 @@ public struct VersionNumber: Equatable, Hashable {
|
||||
)
|
||||
}
|
||||
|
||||
internal func hasSameMajorAndMinorButNewerOrSamePatch(_ version: VersionNumber, _ strict: Bool) -> Bool {
|
||||
internal func hasSameMajorAndMinorButNewerOrSamePatch(_ version: VersionNumber, _ strict: Bool = true) -> Bool {
|
||||
return self.major == version.major && self.minor == version.minor
|
||||
&& self.patch(strict, version) >= version.patch(strict)
|
||||
}
|
||||
|
||||
internal func hasSameMajorButNewerOrSameMinor(_ version: VersionNumber, _ strict: Bool) -> Bool {
|
||||
internal func hasSameMajorButNewerOrSameMinor(_ version: VersionNumber) -> Bool {
|
||||
return self.major == version.major
|
||||
&& self.minor >= version.minor
|
||||
}
|
||||
|
||||
@@ -15,6 +15,13 @@ var Shell: ShellProtocol {
|
||||
class ActiveShell {
|
||||
static var shared: ShellProtocol = RealShell()
|
||||
|
||||
public static func reload() {
|
||||
if shared is RealShell {
|
||||
// Start a new shell, this will re-populate the PATH
|
||||
shared = RealShell()
|
||||
}
|
||||
}
|
||||
|
||||
public static func useTestable(_ expectations: [String: BatchFakeShellOutput]) {
|
||||
Self.shared = TestableShell(expectations: expectations)
|
||||
}
|
||||
|
||||
@@ -278,19 +278,7 @@ class Startup {
|
||||
// =================================================================================
|
||||
EnvironmentCheck(
|
||||
command: {
|
||||
let output = await Shell.pipe("valet --version").out
|
||||
// Failure condition #1: does not contain Laravel Valet
|
||||
if !output.contains("Laravel Valet") {
|
||||
return true
|
||||
}
|
||||
// Failure condition #2: version cannot be parsed
|
||||
let versionString = output
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
.components(separatedBy: "Laravel Valet")[1]
|
||||
.trimmingCharacters(in: .whitespaces)
|
||||
// Extract the version number
|
||||
Valet.shared.version = try! VersionNumber.parse(VersionExtractor.from(versionString)!)
|
||||
// Get the actual version
|
||||
await Valet.shared.updateVersionNumber()
|
||||
return Valet.shared.version == nil
|
||||
},
|
||||
name: "`valet --version` was loaded",
|
||||
|
||||
@@ -84,7 +84,14 @@ import NVAlert
|
||||
)
|
||||
}
|
||||
window = nil
|
||||
|
||||
// Update the internal Valet number because it may have updated
|
||||
await Valet.shared.updateVersionNumber()
|
||||
|
||||
// Update the UI
|
||||
removeBusyStatus()
|
||||
|
||||
// Fire completion callback
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +138,22 @@ class BrewDiagnostics {
|
||||
}
|
||||
}
|
||||
|
||||
public static func verifyThirdPartyTaps() async {
|
||||
let requiredTaps = [
|
||||
"shivammathur/php",
|
||||
"shivammathur/extensions"
|
||||
]
|
||||
|
||||
// Check the status of the installed taps
|
||||
for tap in requiredTaps {
|
||||
if installedTaps.contains(tap) {
|
||||
Log.info("As expected, `\(tap)` is installed!")
|
||||
} else {
|
||||
Log.warn("`\(tap)` does not appear to be installed, will be noted in warnings.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Check if the alias conflict as documented in `checkForCaskConflict` actually occurred.
|
||||
*/
|
||||
|
||||
@@ -51,6 +51,7 @@ class InstallPhpExtensionCommand: BrewCommand {
|
||||
let command = """
|
||||
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
|
||||
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
|
||||
\(Paths.brew) install \(self.installing.map { $0.formulaName }.joined(separator: " ")) --force
|
||||
"""
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ class RemovePhpExtensionCommand: BrewCommand {
|
||||
let command = """
|
||||
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
|
||||
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
|
||||
\(Paths.brew) remove \(phpExtension.formulaName) --force --ignore-dependencies
|
||||
"""
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ class ModifyPhpVersionCommand: BrewCommand {
|
||||
|
||||
// Upgrade the main formula
|
||||
let command = """
|
||||
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
|
||||
\(Paths.brew) upgrade php;
|
||||
\(Paths.brew) install php@\(short);
|
||||
@@ -108,6 +109,7 @@ class ModifyPhpVersionCommand: BrewCommand {
|
||||
}
|
||||
|
||||
let command = """
|
||||
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
|
||||
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
|
||||
\(Paths.brew) upgrade \(self.upgrading.map { $0.name }.joined(separator: " "))
|
||||
|
||||
@@ -33,6 +33,7 @@ class RemovePhpVersionCommand: BrewCommand {
|
||||
))
|
||||
|
||||
let command = """
|
||||
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
|
||||
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
|
||||
\(Paths.brew) remove \(formula) --force --ignore-dependencies
|
||||
|
||||
74
phpmon/Domain/Integrations/Packagist/Packagist.swift
Normal file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Untitled.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 25/08/2025.
|
||||
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Packagist {
|
||||
static func getLatestStableVersion(packageName: String) async throws -> VersionNumber {
|
||||
guard let url = URL(string: "https://repo.packagist.org/p2/\(packageName).json") else {
|
||||
throw PackagistError.invalidURL
|
||||
}
|
||||
|
||||
let agent = "phpmon/\(App.shortVersion)"
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.setValue(agent, forHTTPHeaderField: "User-Agent")
|
||||
|
||||
do {
|
||||
let (data, response) = try await URLSession.shared.data(for: request)
|
||||
|
||||
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
||||
let code = (response as? HTTPURLResponse)?.statusCode ?? 0
|
||||
throw PackagistError.networkError(NSError(domain: "", code: code, userInfo: nil))
|
||||
}
|
||||
|
||||
let decodedResponse = try JSONDecoder()
|
||||
.decode(PackagistP2Response.self, from: data)
|
||||
|
||||
guard let versionsArray = decodedResponse.packages[packageName] else {
|
||||
throw PackagistError.unexpectedResponseStructure
|
||||
}
|
||||
|
||||
// Filter for stable versions using the version_normalized string.
|
||||
// A stable version typically does not have a hyphen (-) indicating a pre-release.
|
||||
let stableVersions = versionsArray.filter { version in
|
||||
guard let versionNormalized = version.version_normalized else {
|
||||
return false
|
||||
}
|
||||
|
||||
// Filter out versions with a hyphen, which are usually unstable.
|
||||
return !versionNormalized.contains("-")
|
||||
}
|
||||
|
||||
// Sort the filtered versions using version_normalized, which is designed for lexicographical sorting.
|
||||
let sortedVersions = stableVersions.sorted { (version1, version2) -> Bool in
|
||||
guard let v1 = version1.version_normalized, let v2 = version2.version_normalized else {
|
||||
return false
|
||||
}
|
||||
return v1.lexicographicallyPrecedes(v2)
|
||||
}
|
||||
|
||||
// The last element of the sorted array is the latest version
|
||||
guard let latestVersionInfo = sortedVersions.last,
|
||||
let latestVersion = latestVersionInfo.version else {
|
||||
throw PackagistError.noStableVersions
|
||||
}
|
||||
|
||||
return try! VersionNumber.parse(latestVersion)
|
||||
} catch {
|
||||
// Catch any errors that occurred and re-throw them as our custom error type for better diagnostics.
|
||||
if let decodingError = error as? DecodingError {
|
||||
throw PackagistError.jsonDecodingError(decodingError)
|
||||
} else if let urlError = error as? URLError {
|
||||
throw PackagistError.networkError(urlError)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
phpmon/Domain/Integrations/Packagist/PackagistError.swift
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// PackagistError.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 25/08/2025.
|
||||
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum PackagistError: Error, LocalizedError {
|
||||
case invalidURL
|
||||
case networkError(Error)
|
||||
case jsonDecodingError(Error)
|
||||
case noStableVersions
|
||||
case unexpectedResponseStructure
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .invalidURL:
|
||||
return "The provided URL is invalid."
|
||||
case .networkError(let error):
|
||||
return "A network error occurred: \(error.localizedDescription)"
|
||||
case .jsonDecodingError(let error):
|
||||
return "Failed to decode JSON: \(error.localizedDescription)"
|
||||
case .noStableVersions:
|
||||
return "No stable versions were found for the package."
|
||||
case .unexpectedResponseStructure:
|
||||
return "The API response structure was not as expected."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// PackagistP2Response.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 25/08/2025.
|
||||
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
struct PackagistP2Response: Codable {
|
||||
let packages: [String: [PackageInfo]]
|
||||
}
|
||||
|
||||
struct PackageInfo: Codable {
|
||||
let version: String?
|
||||
let version_normalized: String?
|
||||
}
|
||||
109
phpmon/Domain/Integrations/Packagist/ValetUpgrader.swift
Normal file
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// ValetUpgrader.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 27/08/2025.
|
||||
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import NVAlert
|
||||
|
||||
class ValetUpgrader {
|
||||
private static func getGlobalComposerJson() -> ComposerJson? {
|
||||
let path = "~/.composer/composer.json".replacingTildeWithHomeDirectory
|
||||
|
||||
do {
|
||||
if FileSystem.fileExists(path) {
|
||||
return try JSONDecoder().decode(
|
||||
ComposerJson.self,
|
||||
from: String(
|
||||
contentsOf: URL(fileURLWithPath: path),
|
||||
encoding: .utf8
|
||||
).data(using: .utf8)!
|
||||
)
|
||||
} else {
|
||||
Log.err("The global Composer file is missing. This should, uh, not happen!")
|
||||
return nil
|
||||
}
|
||||
} catch {
|
||||
Log.err("Something went wrong reading the Composer JSON file.")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public static func showUpgradeAlert() {
|
||||
var valetConstraint: String = "unknown"
|
||||
var constraintCheckPassed: Bool?
|
||||
|
||||
if let json = getGlobalComposerJson(), let dependencies = json.dependencies {
|
||||
if dependencies.keys.contains("laravel/valet") {
|
||||
valetConstraint = dependencies["laravel/valet"]!
|
||||
}
|
||||
}
|
||||
|
||||
guard let latest = Valet.shared.latestVersion else {
|
||||
return Log.err("The latest version is unknown. This should, uh, not happen!")
|
||||
}
|
||||
|
||||
if valetConstraint != "unknown" {
|
||||
// Do a constraint check
|
||||
constraintCheckPassed = !PhpVersionNumberCollection(versions: [latest])
|
||||
.matching(constraint: valetConstraint).isEmpty
|
||||
}
|
||||
|
||||
Task { @MainActor in
|
||||
notifyAboutUpgrade(
|
||||
latest: latest.text,
|
||||
constraint: valetConstraint,
|
||||
passing: constraintCheckPassed ?? false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor private static func upgradeValet() {
|
||||
ComposerWindow().updateGlobalDependencies(
|
||||
notify: true,
|
||||
completion: { success in
|
||||
if success {
|
||||
notifyAboutCompletion()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@MainActor private static func notifyAboutCompletion() {
|
||||
return NVAlert().withInformation(
|
||||
title: "valet_upgraded.title".localized,
|
||||
subtitle: "valet_upgraded.subtitle".localized,
|
||||
description: "valet_upgraded.description".localized,
|
||||
)
|
||||
.withPrimary(text: "generic.ok".localized, action: { vc in
|
||||
vc.close(with: .OK)
|
||||
})
|
||||
.show()
|
||||
}
|
||||
|
||||
@MainActor private static func notifyAboutUpgrade(latest: String, constraint: String, passing: Bool) {
|
||||
let alert = NVAlert().withInformation(
|
||||
title: "valet_upgrade_available.title".localized,
|
||||
subtitle: "valet_upgrade_available.subtitle".localized(latest),
|
||||
description: passing
|
||||
? "valet_upgrade_available.description_constraint_ok".localized(latest)
|
||||
: "valet_upgrade_available.description_constraint_fail".localized(constraint, latest)
|
||||
)
|
||||
.withPrimary(text: "valet_upgrade_available.upgrade".localized, action: { vc in
|
||||
vc.close(with: .OK)
|
||||
ValetUpgrader.upgradeValet()
|
||||
})
|
||||
.withSecondary(text: "valet_upgrade_available.cancel".localized)
|
||||
|
||||
if !passing {
|
||||
_ = alert.withTertiary(text: "valet_upgrade_available.open_composer".localized, action: { _ in
|
||||
MainMenu.shared.openGlobalComposerFolder()
|
||||
})
|
||||
}
|
||||
|
||||
alert.show()
|
||||
}
|
||||
}
|
||||
@@ -9,23 +9,27 @@
|
||||
class FakeDomainScanner: DomainScanner {
|
||||
|
||||
var sites: [ValetSite] = [
|
||||
FakeValetSite(fakeWithName: "laravel", tld: "test", secure: true,
|
||||
path: "~/Code/laravel/framework", linked: true),
|
||||
FakeValetSite(fakeWithName: "larament", tld: "test", secure: true,
|
||||
path: "~/Code/sites/larament", linked: true),
|
||||
|
||||
FakeValetSite(fakeWithName: "tailwind", tld: "test", secure: true,
|
||||
path: "~/Code/tailwind/site", linked: true, constraint: "8.0"),
|
||||
FakeValetSite(fakeWithName: "symfony", tld: "test", secure: true,
|
||||
path: "~/Code/sites/symfony", linked: true, driver: "Symfony (^7.3)"),
|
||||
|
||||
FakeValetSite(fakeWithName: "forge", tld: "test", secure: true,
|
||||
path: "~/Code/laravel/forge", linked: true),
|
||||
|
||||
FakeValetSite(fakeWithName: "concord", tld: "test", secure: false,
|
||||
path: "~/Code/concord", linked: true, driver: "Laravel (^8.0)", constraint: "^7.4", isolated: "7.4"),
|
||||
FakeValetSite(fakeWithName: "tempest", tld: "test", secure: true,
|
||||
path: "~/Code/sites/tempest", linked: true, driver: "Tempest (^1.6)", constraint: "^8.4"),
|
||||
|
||||
FakeValetSite(fakeWithName: "drupal", tld: "test", secure: false,
|
||||
path: "~/Sites/drupal", linked: false, driver: "Drupal", constraint: "^7.4", isolated: "7.4"),
|
||||
path: "~/Sites/drupal", linked: false, driver: "Drupal", constraint: "^8.2", isolated: "8.2"),
|
||||
|
||||
FakeValetSite(fakeWithName: "wordpress", tld: "test", secure: false,
|
||||
path: "~/Sites/wordpress", linked: false, driver: "WordPress", constraint: "^7.4", isolated: "7.4")
|
||||
path: "~/Sites/wordpress", linked: false, driver: "WordPress", constraint: "^8.0", isolated: "8.0"),
|
||||
|
||||
FakeValetSite(fakeWithName: "concord", tld: "test", secure: false,
|
||||
path: "~/Code/concord", linked: true, driver: "Laravel (^10)", constraint: "^8.3", isolated: "8.3"),
|
||||
|
||||
FakeValetSite(fakeWithName: "gen-ai-mcp", tld: "test", secure: true,
|
||||
path: "~/Code/gen-ai-mcp", linked: true, driver: "Laravel (^12)",
|
||||
constraint: "^8.4", isolated: "8.4")
|
||||
]
|
||||
|
||||
var proxies: [ValetProxy] = [
|
||||
|
||||
@@ -15,8 +15,8 @@ class FakeValetSite: ValetSite {
|
||||
secure: Bool,
|
||||
path: String,
|
||||
linked: Bool,
|
||||
driver: String = "Laravel (^9.0)",
|
||||
constraint: String = "^8.1",
|
||||
driver: String = "Laravel (^12)",
|
||||
constraint: String = "^8.4",
|
||||
isolated: String? = nil
|
||||
) {
|
||||
self.init(
|
||||
|
||||
@@ -24,6 +24,9 @@ class Valet {
|
||||
/// The version of Valet that was detected.
|
||||
var version: VersionNumber?
|
||||
|
||||
/// The latest version of Valet, checked via Packagist, if possible.
|
||||
var latestVersion: VersionNumber?
|
||||
|
||||
/// The Valet configuration file.
|
||||
var config: Valet.Configuration!
|
||||
|
||||
@@ -80,6 +83,29 @@ class Valet {
|
||||
return self.shared.sites + self.shared.proxies
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the internal version number of Laravel Valet.
|
||||
If this version number cannot be determined, it fails,
|
||||
and the app cannot start.
|
||||
*/
|
||||
public func updateVersionNumber() async {
|
||||
let output = await Shell.pipe("valet --version").out
|
||||
|
||||
// Failure condition #1: does not contain Laravel Valet
|
||||
if !output.contains("Laravel Valet") {
|
||||
return
|
||||
}
|
||||
|
||||
// Failure condition #2: version cannot be parsed
|
||||
let versionString = output
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
.components(separatedBy: "Laravel Valet")[1]
|
||||
.trimmingCharacters(in: .whitespaces)
|
||||
|
||||
// Extract the version number
|
||||
Valet.shared.version = try? VersionNumber.parse(VersionExtractor.from(versionString)!)
|
||||
}
|
||||
|
||||
/**
|
||||
We don't want to load the initial config.json file as soon as the class is initialised.
|
||||
|
||||
@@ -184,6 +210,28 @@ class Valet {
|
||||
.out.contains("Composer detected issues in your platform")
|
||||
}
|
||||
|
||||
/**
|
||||
Determine if there is a newer version of Laravel Valet available.
|
||||
Checks by verifying the latest version via Packagist (Composer).
|
||||
*/
|
||||
public func checkForUpdates() async {
|
||||
if let currentVersion = self.version,
|
||||
let latestVersion = try? await Packagist.getLatestStableVersion(packageName: "laravel/valet") {
|
||||
self.latestVersion = latestVersion
|
||||
|
||||
if latestVersion.isNewerThan(currentVersion) {
|
||||
Log.info("The latest version of Valet is \(latestVersion.text); current is \(currentVersion.text).")
|
||||
|
||||
// Update the menu so this update is visible.
|
||||
await MainMenu.shared.rebuild()
|
||||
} else {
|
||||
Log.info("You are running the latest version of Valet (\(latestVersion.text)).")
|
||||
}
|
||||
} else {
|
||||
Log.warn("Could not check for latest version of Valet.")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Determine if PHP-FPM is configured correctly.
|
||||
|
||||
|
||||
@@ -56,6 +56,10 @@ extension MainMenu {
|
||||
// Actually detect the PHP versions
|
||||
await PhpEnvironments.detectPhpVersions()
|
||||
|
||||
// Verify third party taps
|
||||
// The missing tap(s) will be actionable later
|
||||
await BrewDiagnostics.verifyThirdPartyTaps()
|
||||
|
||||
// Check for an alias conflict
|
||||
await BrewDiagnostics.checkForCaskConflict()
|
||||
|
||||
@@ -142,6 +146,11 @@ extension MainMenu {
|
||||
|
||||
// Check if the linked version has changed between launches of phpmon
|
||||
await PhpGuard().compareToLastGlobalVersion()
|
||||
|
||||
// Check if Valet has updates, but only if the driver display is enabled
|
||||
if Preferences.isEnabled(.displayDriver) {
|
||||
await Valet.shared.checkForUpdates()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,6 +137,10 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
||||
}
|
||||
}
|
||||
|
||||
@objc func showValetUpgradeAvailableAlert() {
|
||||
ValetUpgrader.showUpgradeAlert()
|
||||
}
|
||||
|
||||
/** Reloads the menu in the background, using `asyncExecution`. */
|
||||
@objc func reloadPhpMonitorMenuInBackground() {
|
||||
asyncExecution({
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import NVAlert
|
||||
|
||||
extension StatusMenu {
|
||||
@MainActor func addLiteModeMenuItem() {
|
||||
@@ -18,11 +19,23 @@ extension StatusMenu {
|
||||
|
||||
@MainActor func addValetVersionItem() {
|
||||
if let version = Valet.shared.version {
|
||||
addItems([
|
||||
var items = [
|
||||
NSMenuItem.separator(),
|
||||
NSMenuItem(title: "mi_driver".localized("Valet \(version.text)"),
|
||||
action: nil, customImage: "ValetDriverIcon")
|
||||
])
|
||||
]
|
||||
|
||||
if let latest = Valet.shared.latestVersion {
|
||||
if latest.isNewerThan(version) {
|
||||
items.append(
|
||||
NSMenuItem(title: "mi_valet_upgrade_action".localized(latest.text),
|
||||
action: #selector(MainMenu.showValetUpgradeAvailableAlert),
|
||||
systemImage: "arrow.up.square.fill")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
addItems(items)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,12 +66,14 @@ class StatusMenu: NSMenu {
|
||||
|
||||
addPreferencesMenuItems()
|
||||
|
||||
if Valet.installed {
|
||||
// Add the menu item displaying the driver information
|
||||
addValetVersionItem()
|
||||
} else {
|
||||
// No driver, using Standalone Mode (internally: lite mode)
|
||||
addLiteModeMenuItem()
|
||||
if Preferences.isEnabled(.displayDriver) {
|
||||
if Valet.installed {
|
||||
// Add the menu item displaying the driver information
|
||||
addValetVersionItem()
|
||||
} else {
|
||||
// No driver, using Standalone Mode (internally: lite mode)
|
||||
addLiteModeMenuItem()
|
||||
}
|
||||
}
|
||||
|
||||
addCoreMenuItems()
|
||||
|
||||
@@ -48,6 +48,7 @@ enum PreferenceName: String, Codable {
|
||||
case displayExtensions = "display_extensions"
|
||||
case displayPresets = "display_presets"
|
||||
case displayMisc = "display_misc"
|
||||
case displayDriver = "display_driver"
|
||||
|
||||
/**
|
||||
What type of data each preference contains.
|
||||
@@ -81,7 +82,8 @@ enum PreferenceName: String, Codable {
|
||||
.displayLimitsWidget,
|
||||
.displayExtensions,
|
||||
.displayPresets,
|
||||
.displayMisc
|
||||
.displayMisc,
|
||||
.displayDriver
|
||||
],
|
||||
.string: [
|
||||
.globalHotkey,
|
||||
|
||||
@@ -72,6 +72,7 @@ class Preferences {
|
||||
PreferenceName.notifyAboutGlobalComposerStatus.rawValue: true,
|
||||
|
||||
/// Preferences: UI Preferences
|
||||
PreferenceName.displayDriver.rawValue: true,
|
||||
PreferenceName.displayGlobalVersionSwitcher.rawValue: true,
|
||||
PreferenceName.displayServicesManager.rawValue: true,
|
||||
PreferenceName.displayValetIntegration.rawValue: true,
|
||||
|
||||
@@ -55,7 +55,8 @@ class MenuStructurePreferencesVC: GenericPreferenceVC {
|
||||
let vc = NSStoryboard(name: "Main", bundle: nil)
|
||||
.instantiateController(withIdentifier: "preferencesTemplateVC") as! GenericPreferenceVC
|
||||
|
||||
_ = vc.addView(when: true, vc.displayFeature("prefs.display_global_version_switcher", .displayGlobalVersionSwitcher, true))
|
||||
return vc
|
||||
.addView(when: true, vc.displayFeature("prefs.display_global_version_switcher", .displayGlobalVersionSwitcher, true))
|
||||
.addView(when: Valet.installed, vc.displayFeature("prefs.display_services_manager", .displayServicesManager))
|
||||
.addView(when: Valet.installed, vc.displayFeature("prefs.display_valet_integration", .displayValetIntegration))
|
||||
.addView(when: true, vc.displayFeature("prefs.display_php_config_finder", .displayPhpConfigFinder))
|
||||
@@ -64,8 +65,7 @@ class MenuStructurePreferencesVC: GenericPreferenceVC {
|
||||
.addView(when: true, vc.displayFeature("prefs.display_extensions", .displayExtensions))
|
||||
.addView(when: true, vc.displayFeature("prefs.display_presets", .displayPresets))
|
||||
.addView(when: true, vc.displayFeature("prefs.display_misc", .displayMisc))
|
||||
|
||||
return vc
|
||||
.addView(when: true, vc.displayFeature("prefs.display_driver", .displayDriver))
|
||||
}
|
||||
// swiftlint:enable line_length
|
||||
}
|
||||
@@ -76,15 +76,13 @@ class NotificationPreferencesVC: GenericPreferenceVC {
|
||||
let vc = NSStoryboard(name: "Main", bundle: nil)
|
||||
.instantiateController(withIdentifier: "preferencesTemplateVC") as! GenericPreferenceVC
|
||||
|
||||
_ = vc.addView(when: true, vc.getNotifyAboutVersionChangePV())
|
||||
return vc.addView(when: true, vc.getNotifyAboutVersionChangePV())
|
||||
.addView(when: true, vc.getNotifyAboutPresetsPV())
|
||||
.addView(when: Valet.installed, vc.getNotifyAboutSecureTogglePV())
|
||||
.addView(when: true, vc.getNotifyAboutGlobalComposerStatusPV())
|
||||
.addView(when: true, vc.getNotifyAboutServicesPV())
|
||||
.addView(when: Valet.installed, vc.getNotifyAboutPhpFpmChangePV())
|
||||
.addView(when: Valet.installed, vc.getWarnAboutNonStandardTldPV())
|
||||
|
||||
return vc
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
25
phpmon/Domain/Provision/InstallHomebrew.swift
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// InstallHomebrew.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 01/08/2025.
|
||||
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
class InstallHomebrew {
|
||||
public func run() async throws {
|
||||
let script = """
|
||||
NONINTERACTIVE=1 /bin/bash -c \
|
||||
"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
"""
|
||||
|
||||
_ = try await Shell.attach(script, didReceiveOutput: { (string: String, _: ShellStream) in
|
||||
print(string)
|
||||
}, withTimeout: 60 * 10)
|
||||
}
|
||||
|
||||
public func verify() async {
|
||||
// Make sure the Homebrew directory exists
|
||||
// Make sure the `brew` binary exists
|
||||
}
|
||||
}
|
||||
40
phpmon/Domain/Provision/ZshRunCommand.swift
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Provision+zshrc.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 01/08/2025.
|
||||
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
class ZshRunCommand {
|
||||
/**
|
||||
Adds a given line to .zshrc, which may be needed to adjust the PATH.
|
||||
*/
|
||||
private func add(_ text: String) async -> Bool {
|
||||
let outcome = await Shell.pipe("""
|
||||
touch ~/.zshrc && \
|
||||
grep -qxF '\(text)' ~/.zshrc \
|
||||
|| echo '\n\n\(text)\n' >> ~/.zshrc
|
||||
""")
|
||||
|
||||
if outcome.hasError {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
Adds Homebrew binaries to the PATH.
|
||||
*/
|
||||
public func addHomebrewPath() async {
|
||||
_ = await add("export PATH=$HOME/bin:/opt/homebrew/bin:$PATH")
|
||||
}
|
||||
|
||||
/**
|
||||
Adds PHP Monitor binaries to the PATH.
|
||||
*/
|
||||
public func addPhpMonitorPath() async {
|
||||
_ = await add("export PATH=$HOME/bin:~/.config/phpmon/bin:$PATH")
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ struct Warning: Identifiable, Hashable {
|
||||
let title: String
|
||||
let paragraphs: () -> [String]
|
||||
let url: String?
|
||||
let fix: (() async -> Void)?
|
||||
|
||||
/**
|
||||
- Parameters:
|
||||
@@ -23,19 +24,22 @@ struct Warning: Identifiable, Hashable {
|
||||
- title: The title displayed for the user
|
||||
- paragraphs: The main body of text displayed for the user
|
||||
- url: The URL that one can navigate to for more information (if applicable)
|
||||
- fix: The automatic fix that can be applied (if applicable)
|
||||
*/
|
||||
init(
|
||||
command: @escaping () async -> Bool,
|
||||
name: String,
|
||||
title: String,
|
||||
paragraphs: @escaping () -> [String],
|
||||
url: String?
|
||||
url: String?,
|
||||
fix: (() async -> Void)?
|
||||
) {
|
||||
self.command = command
|
||||
self.name = name
|
||||
self.title = title
|
||||
self.paragraphs = paragraphs
|
||||
self.url = url
|
||||
self.fix = fix
|
||||
}
|
||||
|
||||
public func applies() async -> Bool {
|
||||
|
||||
@@ -36,7 +36,8 @@ class WarningManager: ObservableObject {
|
||||
name: "Running PHP Monitor with Rosetta on M1",
|
||||
title: "warnings.arm_compatibility.title",
|
||||
paragraphs: { return ["warnings.arm_compatibility.description"] },
|
||||
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-and-Apple-Silicon"
|
||||
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-and-Apple-Silicon",
|
||||
fix: nil
|
||||
),
|
||||
Warning(
|
||||
command: {
|
||||
@@ -50,7 +51,75 @@ class WarningManager: ObservableObject {
|
||||
"warnings.helper_permissions.unavailable",
|
||||
"warnings.helper_permissions.symlink"
|
||||
] },
|
||||
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries"
|
||||
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries",
|
||||
fix: Paths.shell == "/bin/zsh" ? {
|
||||
// Add to PATH
|
||||
await ZshRunCommand().addPhpMonitorPath()
|
||||
// Finally, perform environment checks again
|
||||
await WarningManager.shared.checkEnvironment()
|
||||
} : nil
|
||||
),
|
||||
Warning(
|
||||
command: {
|
||||
PhpEnvironments.shared.currentInstall?.extensions.contains { $0.name == "xdebug" } ?? false
|
||||
&& !Xdebug.enabled
|
||||
},
|
||||
name: "Missing configuration file for `xdebug.mode`",
|
||||
title: "warnings.xdebug_conf_missing.title",
|
||||
paragraphs: { return [
|
||||
"warnings.xdebug_conf_missing.description"
|
||||
] },
|
||||
url: "https://xdebug.org/docs/install#mode",
|
||||
fix: {
|
||||
if let php = PhpEnvironments.shared.currentInstall {
|
||||
if let xdebug = php.extensions.first(where: { $0.name == "xdebug" }),
|
||||
let original = try? FileSystem.getStringFromFile(xdebug.file) {
|
||||
// Append xdebug.mode = off to the file
|
||||
try? FileSystem.writeAtomicallyToFile(
|
||||
xdebug.file,
|
||||
content: original + "\nxdebug.mode = off"
|
||||
)
|
||||
|
||||
// Reload extension configuration by updating PHP installation info (reload)
|
||||
PhpEnvironments.shared.currentInstall = ActivePhpInstallation()
|
||||
|
||||
// Finally, reload warnings
|
||||
await WarningManager.shared.checkEnvironment()
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
Warning(
|
||||
command: {
|
||||
!BrewDiagnostics.installedTaps.contains("shivammathur/php")
|
||||
},
|
||||
name: "`shivammathur/php` tap is missing",
|
||||
title: "warnings.php_tap_missing.title",
|
||||
paragraphs: { return [
|
||||
"warnings.php_tap_missing.description"
|
||||
] },
|
||||
url: "https://github.com/shivammathur/homebrew-php",
|
||||
fix: {
|
||||
await Shell.quiet("brew tap shivammathur/php")
|
||||
await BrewDiagnostics.loadInstalledTaps()
|
||||
await WarningManager.shared.checkEnvironment()
|
||||
}
|
||||
),
|
||||
Warning(
|
||||
command: {
|
||||
!BrewDiagnostics.installedTaps.contains("shivammathur/extensions")
|
||||
},
|
||||
name: "`shivammathur/extensions` tap is missing",
|
||||
title: "warnings.extensions_tap_missing.title",
|
||||
paragraphs: { return [
|
||||
"warnings.extensions_tap_missing.description"
|
||||
] },
|
||||
url: "https://github.com/shivammathur/homebrew-extensions",
|
||||
fix: {
|
||||
await Shell.quiet("brew tap shivammathur/extensions")
|
||||
await BrewDiagnostics.loadInstalledTaps()
|
||||
await WarningManager.shared.checkEnvironment()
|
||||
}
|
||||
),
|
||||
Warning(
|
||||
command: {
|
||||
@@ -64,7 +133,8 @@ class WarningManager: ObservableObject {
|
||||
PhpConfigChecker.shared.missing.joined(separator: "\n• ")
|
||||
)
|
||||
] },
|
||||
url: nil
|
||||
url: nil,
|
||||
fix: nil
|
||||
)
|
||||
]
|
||||
|
||||
@@ -88,6 +158,10 @@ class WarningManager: ObservableObject {
|
||||
Checks the user's environment and checks if any special warnings apply.
|
||||
*/
|
||||
func checkEnvironment() async {
|
||||
ActiveShell.reload()
|
||||
|
||||
await BrewDiagnostics.loadInstalledTaps()
|
||||
|
||||
if ProcessInfo.processInfo.environment["EXTREME_DOCTOR_MODE"] != nil {
|
||||
self.temporaryWarnings = self.evaluations
|
||||
await self.broadcastWarnings()
|
||||
|
||||
@@ -76,7 +76,8 @@ struct PhpDoctorView: View {
|
||||
WarningView(
|
||||
title: warning.title,
|
||||
paragraphs: warning.paragraphs(),
|
||||
documentationUrl: warning.url
|
||||
documentationUrl: warning.url,
|
||||
automaticFix: warning.fix
|
||||
)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class PhpDoctorWindowController: PMWindowController {
|
||||
|
||||
guard let window = windowController.window else { return }
|
||||
window.title = ""
|
||||
window.styleMask = [.titled, .closable, .miniaturizable]
|
||||
window.styleMask = [.titled, .closable, .miniaturizable, .resizable]
|
||||
window.titlebarAppearsTransparent = true
|
||||
window.delegate = delegate ?? windowController
|
||||
window.contentView = NSHostingView(rootView: PhpDoctorView())
|
||||
|
||||
@@ -12,6 +12,8 @@ struct WarningView: View {
|
||||
@State var title: String
|
||||
@State var paragraphs: [String]
|
||||
@State var documentationUrl: String?
|
||||
@State var automaticFix: (() async -> Void)?
|
||||
@State var busyFixing: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
@@ -36,9 +38,38 @@ struct WarningView: View {
|
||||
minHeight: 0, maxHeight: .infinity,
|
||||
alignment: .topLeading
|
||||
)
|
||||
if documentationUrl != nil {
|
||||
Button("Learn More") {
|
||||
NSWorkspace.shared.open(URL(string: documentationUrl!)!)
|
||||
|
||||
HStack {
|
||||
if let automaticFix {
|
||||
Button(
|
||||
action: {
|
||||
Task {
|
||||
busyFixing = true
|
||||
await automaticFix()
|
||||
busyFixing = false
|
||||
}
|
||||
},
|
||||
label: {
|
||||
Text("Fix Automatically")
|
||||
}
|
||||
)
|
||||
.disabled(busyFixing) }
|
||||
|
||||
if let documentationUrl {
|
||||
Button("Learn More") {
|
||||
NSWorkspace.shared.open(URL(string: documentationUrl)!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if busyFixing {
|
||||
HStack {
|
||||
ProgressView()
|
||||
.progressViewStyle(CircularProgressViewStyle())
|
||||
.scaleEffect(0.6)
|
||||
Text("warnings.being_fixed.description".localizedForSwiftUI)
|
||||
.font(.system(size: 12))
|
||||
.foregroundStyle(Color.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ struct PhpVersionManagerView: View {
|
||||
)
|
||||
}
|
||||
|
||||
// Finally, load PHP information
|
||||
await PhpEnvironments.detectPhpVersions()
|
||||
await self.handler.refreshPhpVersions(loadOutdated: false)
|
||||
await self.handler.refreshPhpVersions(loadOutdated: true)
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
"mi_quit" = "Quit PHP Monitor";
|
||||
"mi_about" = "About PHP Monitor";
|
||||
|
||||
"mi_valet_upgrade_available" = "An updated version of Valet is available.";
|
||||
"mi_valet_upgrade_action" = "Upgrade to Valet %@...";
|
||||
|
||||
"mi_presets_title" = "Configuration Presets";
|
||||
"mi_apply_presets_title" = "Apply Configuration Presets";
|
||||
"mi_revert_to_prev_config" = "Revert to Previous Configuration...";
|
||||
@@ -467,6 +470,9 @@ This has no effect on other terminals, only for the particular terminal session
|
||||
"prefs.warn_about_non_standard_tld_desc" = "If you use a non-standard TLD, you may not wish to get repeated notifications about this.";
|
||||
"prefs.warn_about_non_standard_tld" = "Warn about non-standard TLD";
|
||||
|
||||
"prefs.display_driver_desc" = "If disabled, you will not be able to see which driver is in use. If Valet is active, the version number will also no longer be visible, and you will not be notified about updates to Valet in the menu.";
|
||||
"prefs.display_driver" = "Driver & Updates";
|
||||
|
||||
"prefs.display_global_version_switcher_desc" = "If disabled, you will not be able to change the globally linked PHP version via the main menu.";
|
||||
"prefs.display_global_version_switcher" = "PHP Switcher";
|
||||
|
||||
@@ -816,12 +822,13 @@ COMMON TROUBLESHOOTING TIPS
|
||||
|
||||
"warnings.limits_error.title" = "PHP Monitor could not retrieve limits.";
|
||||
"warnings.limits_error.steps" = "Try running ‘php -v’ in your terminal.";
|
||||
"warnings.being_fixed.description" = "PHP Monitor is addressing this issue. Please wait a bit.";
|
||||
|
||||
"warnings.title" = "PHP Doctor";
|
||||
"warnings.description" = "**PHP Doctor** will suggest improvements to your active system configuration.";
|
||||
"warnings.disclaimer" = "You may choose to hide all recommendations from the PHP Monitor menu in Preferences, but it is recommended that you deal with all actionable items.";
|
||||
"warnings.refresh.button" = "Scan Again";
|
||||
"warnings.refresh.button.description" = "Press this button once you've fixed an issue. This will cause PHP Monitor to re-evaluate your environment. If it's really fixed, the recommendation should disappear.";
|
||||
"warnings.refresh.button.description" = "Press this button if you've manually fixed an issue. This will cause PHP Monitor to re-evaluate your environment. (Automatic fixes do not require you to press this button.)";
|
||||
|
||||
"warnings.helper_permissions.title" = "PHP Monitor’s helpers are currently unavailable.";
|
||||
"warnings.helper_permissions.description" = "PHP Monitor comes with various helper scripts. Using these scripts allows you to easily invoke a specific version of PHP without switching the linked PHP version.";
|
||||
@@ -838,6 +845,15 @@ COMMON TROUBLESHOOTING TIPS
|
||||
|
||||
When files like these are missing, you should switch to the PHP version associated with those files: that may resolve the problem. If this doesn't fix the issue, it's recommended to reinstall the appropriate PHP version(s) via Homebrew again, which should restore the configuration files that are missing. Missing configuration files can be the reason why you get '502 Bad Gateway' errors, even after running Fix My Valet (if you are using Valet).";
|
||||
|
||||
"warnings.xdebug_conf_missing.title" = "Xdebug configuration is incomplete";
|
||||
"warnings.xdebug_conf_missing.description" = "You have Xdebug installed, but no mode is specified. Would you like for PHP Monitor to update your configuration? You can also fix this manually.";
|
||||
|
||||
"warnings.php_tap_missing.title" = "`shivammathur/php` tap is missing";
|
||||
"warnings.php_tap_missing.description" = "This Homebrew tap is required to install older PHP versions via this app's PHP Version Manager.";
|
||||
|
||||
"warnings.extensions_tap_missing.title" = "`shivammathur/extensions` tap is missing";
|
||||
"warnings.extensions_tap_missing.description" = "This Homebrew tap is required to install extensions via this app's PHP Extension Manager.";
|
||||
|
||||
"warnings.none" = "There are no recommendations available for you right now. You're all good!";
|
||||
|
||||
// ONBOARDING
|
||||
@@ -878,3 +894,21 @@ Please note that some features (greyed out below) are currently unavailable beca
|
||||
It is recommended to restart PHP Monitor afterwards. Learn more about this issue at: https://github.com/nicoverbruggen/phpmon/issues/294.
|
||||
|
||||
If PHP Monitor has finished initializing anyway or you want to wait a bit longer, feel free to click 'Ignore' and use PHP Monitor as usual. Either way, you may want to investigate, because this isn't supposed to take this long.";
|
||||
|
||||
// VALET UPGRADES
|
||||
|
||||
"valet_upgrade_available.title" = "Do you want to upgrade Valet to the latest compatible version?";
|
||||
"valet_upgrade_available.subtitle" = "Laravel Valet %@ is available. PHP Monitor can update your global Composer dependencies for you.";
|
||||
"valet_upgrade_available.description_constraint_ok" = "Given your global Composer setup, the latest version that will be installed should be the very latest, Laravel Valet %@.";
|
||||
"valet_upgrade_available.description_constraint_fail" = "Please note that given your global Composer setup, the latest version that can be automatically installed WILL NOT be latest version available. This is due to constraints in your global `composer.json` file.
|
||||
|
||||
Your version constraint for Valet is: `%@`, which prohibits the installation of Valet %@.
|
||||
|
||||
If you want to make edits to this file, please do so before upgrading. When you see this message, you should probably check Valet's release notes, as Valet's requirements may have changed.";
|
||||
"valet_upgrade_available.upgrade" = "Upgrade";
|
||||
"valet_upgrade_available.cancel" = "Cancel";
|
||||
"valet_upgrade_available.open_composer" = "Locate `composer.json`";
|
||||
|
||||
"valet_upgraded.title" = "Valet has been upgraded!";
|
||||
"valet_upgraded.subtitle" = "Sometimes, upgrades may require you to run `valet install` in a terminal after upgrading.";
|
||||
"valet_upgraded.description" = "PHP Monitor cannot know if this is necessary, so it doesn't do this automatically. However, if things don't seem to work correctly, you can try running `valet install` again and restart PHP Monitor.";
|
||||
|
||||
50
tests/Shared/TestBundle.swift
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// BundleHelper.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 25/08/2025.
|
||||
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
This file is used to access bundle resources via test structs
|
||||
that cannot access the bundle via the previous class syntax.
|
||||
|
||||
After converting a test to Swift Testing, this is no longer possible:
|
||||
|
||||
```swift
|
||||
class MyTest: XCTestCase {
|
||||
static var configurationFileUrl: URL {
|
||||
return Bundle(for: Self.self).url(
|
||||
forResource: "valet-config",
|
||||
withExtension: "json"
|
||||
)!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Normally, we would be able to access the bundle via the class
|
||||
itself, but we'd prefer _not_ to make this accessible to other
|
||||
classes. Thankfully, this is where `fileprivate` shines.
|
||||
|
||||
The bundle is now accessed via `TestBundleClass`, which is not
|
||||
accessible outside the scope of this file. `TestBundle` as a
|
||||
global variable, though, is!
|
||||
|
||||
Usage:
|
||||
|
||||
```swift
|
||||
return TestBundle.url(
|
||||
forResource: "valet-config",
|
||||
withExtension: "json"
|
||||
)!
|
||||
```
|
||||
*/
|
||||
|
||||
fileprivate class TestBundleClass {}
|
||||
|
||||
public var TestBundle: Bundle {
|
||||
return Bundle(for: TestBundleClass.self)
|
||||
}
|
||||
@@ -6,21 +6,23 @@
|
||||
// Copyright © 2023 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Testing
|
||||
|
||||
class CommandTest: XCTestCase {
|
||||
@Suite("Commands")
|
||||
struct CommandTest {
|
||||
|
||||
func test_determine_php_version() {
|
||||
@Test
|
||||
func determinePhpVersion() {
|
||||
let version = Command.execute(
|
||||
path: Paths.php,
|
||||
arguments: ["-v"],
|
||||
trimNewlines: false
|
||||
)
|
||||
|
||||
XCTAssert(version.contains("(cli)"))
|
||||
XCTAssert(version.contains("NTS"))
|
||||
XCTAssert(version.contains("built"))
|
||||
XCTAssert(version.contains("Zend"))
|
||||
#expect(version.contains("(cli)"))
|
||||
#expect(version.contains("NTS"))
|
||||
#expect(version.contains("built"))
|
||||
#expect(version.contains("Zend"))
|
||||
}
|
||||
|
||||
}
|
||||
19
tests/unit/_ST/Integration/PackagistTest.swift
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// PackagistTest.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 25/08/2025.
|
||||
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@Suite("Integration")
|
||||
struct PackagistTest {
|
||||
@Test func canRetrieveLaravelValetVersion() async {
|
||||
let packageToCheck = "laravel/valet"
|
||||
let latestVersion = try? await Packagist.getLatestStableVersion(packageName: packageToCheck)
|
||||
|
||||
#expect(latestVersion != nil)
|
||||
}
|
||||
}
|
||||
@@ -6,18 +6,20 @@
|
||||
// Copyright © 2023 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class ValetConfigurationTest: XCTestCase {
|
||||
import Testing
|
||||
import Foundation
|
||||
|
||||
@Suite("Parsers")
|
||||
struct ValetConfigurationTest {
|
||||
static var jsonConfigFileUrl: URL {
|
||||
return Bundle(for: Self.self).url(
|
||||
return TestBundle.url(
|
||||
forResource: "valet-config",
|
||||
withExtension: "json"
|
||||
)!
|
||||
}
|
||||
|
||||
func test_can_load_config_file() throws {
|
||||
@Test("Can load config file")
|
||||
func can_load_config_file() throws {
|
||||
let json = try? String(
|
||||
contentsOf: Self.jsonConfigFileUrl,
|
||||
encoding: .utf8
|
||||
@@ -27,13 +29,13 @@ class ValetConfigurationTest: XCTestCase {
|
||||
from: json!.data(using: .utf8)!
|
||||
)
|
||||
|
||||
XCTAssertEqual(config.tld, "test")
|
||||
XCTAssertEqual(config.paths, [
|
||||
#expect(config.tld == "test")
|
||||
#expect(config.paths == [
|
||||
"/Users/username/.config/valet/Sites",
|
||||
"/Users/username/Sites"
|
||||
])
|
||||
XCTAssertEqual(config.defaultSite, "/Users/username/default-site")
|
||||
XCTAssertEqual(config.loopback, "127.0.0.1")
|
||||
#expect(config.defaultSite == "/Users/username/default-site")
|
||||
#expect(config.loopback == "127.0.0.1")
|
||||
}
|
||||
|
||||
}
|
||||