diff --git a/DEVELOPER.md b/DEVELOPER.md index f06f564..5f9cb1f 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -13,6 +13,20 @@ Once you have downloaded this repository, open `PHP Monitor.xcodeproj`, and you If you'd like to create a production build, choose "Any Mac" as the target and select Product > Archive. +## 🚀 Release procedure + +1. Merge into `main` +2. Create tag +3. Add changes to changelog + update security document +4. Archive +5. Notarize and prepare for own distribution +6. After notarization, export .app +7. Create zipped version +8. Calculate SHA256: `openssl dgst -sha256 phpmon.zip` +9. Upload to GitHub and add to tagged release +10. Update Cask with new version + hash +11. Check new version can be installed via Cask + ## 🐛 Symbolication of crashes If you have an archived build of the app and exported the DSYM, it is possible to symbolicate .ips crash logs. diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 01baff1..2e1d349 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -28,10 +28,13 @@ C4068CA827B07A1300544CD5 /* SelectPreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA627B07A1300544CD5 /* SelectPreferenceView.swift */; }; C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */; }; C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */; }; + C4080FF627BD8C6400BF2C6B /* BetterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */; }; + C4080FF727BD8C6400BF2C6B /* BetterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */; }; + C4080FFA27BD956700BF2C6B /* BetterAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */; }; + C4080FFB27BD956700BF2C6B /* BetterAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */; }; C40B24F127A3106D0018C7D2 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E67279DE0540010F296 /* ServicesView.swift */; }; C40B24F227A310770018C7D2 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; }; C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47331A1247093B7009A0597 /* StatusMenu.swift */; }; - C40B24F527A3108B0018C7D2 /* Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E6C279DF87A0010F296 /* Async.swift */; }; C40C7F1E2772136000DDDCDC /* PhpEnv.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F1D2772136000DDDCDC /* PhpEnv.swift */; }; C40C7F1F2772136000DDDCDC /* PhpEnv.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F1D2772136000DDDCDC /* PhpEnv.swift */; }; C40C7F2827721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */; }; @@ -62,6 +65,7 @@ C4232EE52612526500158FC6 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = C4232EE42612526500158FC6 /* Credits.html */; }; C42759672627662800093CAE /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42759662627662800093CAE /* NSMenuExtension.swift */; }; C42759682627662800093CAE /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42759662627662800093CAE /* NSMenuExtension.swift */; }; + C42C49DB27C2806F0074ABAC /* MainMenu+FixMyValet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42C49DA27C2806F0074ABAC /* MainMenu+FixMyValet.swift */; }; C43603A0275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */; }; C43603A1275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */; }; C43A8A1A25D9CD1000591B77 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43A8A1925D9CD1000591B77 /* Utility.swift */; }; @@ -112,7 +116,7 @@ C4AF9F78275447F100D44ED0 /* ValetConfigParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F76275447F100D44ED0 /* ValetConfigParserTest.swift */; }; C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F792754499000D44ED0 /* Valet.swift */; }; C4AF9F7B2754499000D44ED0 /* Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F792754499000D44ED0 /* Valet.swift */; }; - C4AF9F7D275454A900D44ED0 /* ValetTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F7C275454A900D44ED0 /* ValetTest.swift */; }; + C4AF9F7D275454A900D44ED0 /* ValetVersionExtractorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F7C275454A900D44ED0 /* ValetVersionExtractorTest.swift */; }; C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5635D276AB09000F12CCB /* VersionExtractor.swift */; }; C4B5635F276AB09000F12CCB /* VersionExtractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5635D276AB09000F12CCB /* VersionExtractor.swift */; }; C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */; }; @@ -128,6 +132,10 @@ C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */; }; C4B97B7B275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */; }; C4B97B7C275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */; }; + C4BF90C127C57C220054E78C /* MainMenu+FixMyValet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42C49DA27C2806F0074ABAC /* MainMenu+FixMyValet.swift */; }; + C4C1019627C659B7001FACC2 /* HotKey in Frameworks */ = {isa = PBXBuildFile; productRef = C4C1019527C659B7001FACC2 /* HotKey */; }; + C4C1019B27C65C6F001FACC2 /* Process.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C1019A27C65C6F001FACC2 /* Process.swift */; }; + C4C1019C27C65C6F001FACC2 /* Process.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C1019A27C65C6F001FACC2 /* Process.swift */; }; C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */; }; C4C3ED4327834C5200AB15D8 /* CustomPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3ED4227834C5200AB15D8 /* CustomPrefs.swift */; }; C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; @@ -137,9 +145,9 @@ C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CCBA6B275C567B008C7055 /* PMWindowController.swift */; }; C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CCBA6B275C567B008C7055 /* PMWindowController.swift */; }; C4CE3BB827B31F2E0086CA49 /* MainMenu+Switcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB727B31F2E0086CA49 /* MainMenu+Switcher.swift */; }; - C4CE3BBA27B31F670086CA49 /* MainMenu+Composer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* MainMenu+Composer.swift */; }; + C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */; }; C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB727B31F2E0086CA49 /* MainMenu+Switcher.swift */; }; - C4CE3BBC27B324250086CA49 /* MainMenu+Composer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* MainMenu+Composer.swift */; }; + C4CE3BBC27B324250086CA49 /* ComposerWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */; }; C4D8016622B1584700C6DA1B /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; }; C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; }; C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */; }; @@ -147,9 +155,12 @@ C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */; }; C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */; }; C4DEB7D427A5D60B00834718 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DEB7D327A5D60B00834718 /* Stats.swift */; }; + C4E0F7ED27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */; }; + C4E0F7EE27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */; }; + C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E4404527C56F4700D225E1 /* ValetSite.swift */; }; + C4E4404727C56F4700D225E1 /* ValetSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E4404527C56F4700D225E1 /* ValetSite.swift */; }; C4EC1E66279DE0380010F296 /* ServicesView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C4EC1E65279DE0380010F296 /* ServicesView.xib */; }; C4EC1E68279DE0540010F296 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E67279DE0540010F296 /* ServicesView.swift */; }; - C4EC1E6D279DF87A0010F296 /* Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E6C279DF87A0010F296 /* Async.swift */; }; C4EC1E73279DFCF40010F296 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; }; C4EE188422D3386B00E126E5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE188322D3386B00E126E5 /* Constants.swift */; }; C4EE55A927708B9E001DF387 /* PMHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE55A627708B9E001DF387 /* PMHeaderView.swift */; }; @@ -217,6 +228,8 @@ C4068CA327B0780A00544CD5 /* CheckboxPreferenceView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CheckboxPreferenceView.xib; sourceTree = ""; }; C4068CA627B07A1300544CD5 /* SelectPreferenceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectPreferenceView.swift; sourceTree = ""; }; C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarIcons.swift; sourceTree = ""; }; + C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterAlert.swift; sourceTree = ""; }; + C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterAlertVC.swift; sourceTree = ""; }; C40C7F1D2772136000DDDCDC /* PhpEnv.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpEnv.swift; sourceTree = ""; }; C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActivePhpInstallation+Checks.swift"; sourceTree = ""; }; C40C7F2F27722E8D00DDDCDC /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; @@ -240,6 +253,7 @@ C41E87192763D42300161EE0 /* SiteListVC+ContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SiteListVC+ContextMenu.swift"; sourceTree = ""; }; C4232EE42612526500158FC6 /* Credits.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = Credits.html; sourceTree = ""; }; C42759662627662800093CAE /* NSMenuExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSMenuExtension.swift; sourceTree = ""; }; + C42C49DA27C2806F0074ABAC /* MainMenu+FixMyValet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+FixMyValet.swift"; sourceTree = ""; }; C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Notifications.swift"; sourceTree = ""; }; C43A8A1925D9CD1000591B77 /* Utility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = ""; }; C43A8A1F25D9D1D700591B77 /* brew.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = brew.json; sourceTree = ""; }; @@ -273,7 +287,7 @@ C4AF9F70275445FF00D44ED0 /* valet-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "valet-config.json"; sourceTree = ""; }; C4AF9F76275447F100D44ED0 /* ValetConfigParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetConfigParserTest.swift; sourceTree = ""; }; C4AF9F792754499000D44ED0 /* Valet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Valet.swift; sourceTree = ""; }; - C4AF9F7C275454A900D44ED0 /* ValetTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetTest.swift; sourceTree = ""; }; + C4AF9F7C275454A900D44ED0 /* ValetVersionExtractorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetVersionExtractorTest.swift; sourceTree = ""; }; C4B5635D276AB09000F12CCB /* VersionExtractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionExtractor.swift; sourceTree = ""; }; C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionExtractorTest.swift; sourceTree = ""; }; C4B5853B2770FE3900DA4FBE /* Paths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Paths.swift; sourceTree = ""; }; @@ -282,23 +296,25 @@ C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+MenuOutlets.swift"; sourceTree = ""; }; C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+ActivationPolicy.swift"; sourceTree = ""; }; C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+GlobalHotkey.swift"; sourceTree = ""; }; + C4C1019A27C65C6F001FACC2 /* Process.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Process.swift; sourceTree = ""; }; C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Startup.swift"; sourceTree = ""; }; C4C3ED4227834C5200AB15D8 /* CustomPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPrefs.swift; sourceTree = ""; }; C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "App+ConfigWatch.swift"; sourceTree = ""; }; C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpConfigWatcher.swift; sourceTree = ""; }; C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = ""; }; C4CE3BB727B31F2E0086CA49 /* MainMenu+Switcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Switcher.swift"; sourceTree = ""; }; - C4CE3BB927B31F670086CA49 /* MainMenu+Composer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Composer.swift"; sourceTree = ""; }; + C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerWindow.swift; sourceTree = ""; }; C4D8016522B1584700C6DA1B /* Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Startup.swift; sourceTree = ""; }; C4D89BC52783C99400A02B68 /* ComposerJson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerJson.swift; sourceTree = ""; }; C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpSwitcher.swift; sourceTree = ""; }; C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalSwitcher.swift; sourceTree = ""; }; C4DEB7D327A5D60B00834718 /* Stats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stats.swift; sourceTree = ""; }; + C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSWindowExtension.swift; sourceTree = ""; }; + C4E4404527C56F4700D225E1 /* ValetSite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetSite.swift; sourceTree = ""; }; C4E713562570150F00007428 /* SECURITY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = SECURITY.md; sourceTree = ""; }; C4E713572570151400007428 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = ""; }; C4EC1E65279DE0380010F296 /* ServicesView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ServicesView.xib; sourceTree = ""; }; C4EC1E67279DE0540010F296 /* ServicesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServicesView.swift; sourceTree = ""; }; - C4EC1E6C279DF87A0010F296 /* Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Async.swift; sourceTree = ""; }; C4EC1E72279DFCF40010F296 /* Events.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Events.swift; sourceTree = ""; }; C4EE188322D3386B00E126E5 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; C4EE55A627708B9E001DF387 /* PMHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMHeaderView.swift; sourceTree = ""; }; @@ -309,7 +325,6 @@ C4F2E4392752F7D00020E974 /* PhpInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpInstallation.swift; sourceTree = ""; }; C4F30B02278E16BA00755FCE /* HomebrewService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewService.swift; sourceTree = ""; }; C4F30B06278E195800755FCE /* brew-services.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "brew-services.json"; sourceTree = ""; }; - C4F7807425D7F7E5000DBC97 /* RELEASE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = RELEASE.md; sourceTree = ""; }; C4F7807925D7F84B000DBC97 /* phpmon-tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "phpmon-tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; C4F7807D25D7F84B000DBC97 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C4F7809B25D80344000DBC97 /* CommandTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandTest.swift; sourceTree = ""; }; @@ -333,6 +348,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C4C1019627C659B7001FACC2 /* HotKey in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -389,6 +405,15 @@ path = IAP; sourceTree = ""; }; + C4080FF827BD955900BF2C6B /* Notice */ = { + isa = PBXGroup; + children = ( + C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */, + C4080FF927BD956700BF2C6B /* BetterAlertVC.swift */, + ); + path = Notice; + sourceTree = ""; + }; C40C7F1C27720E1400DDDCDC /* Test Files */ = { isa = PBXGroup; children = ( @@ -409,6 +434,7 @@ C4B5853D2770FE3900DA4FBE /* Command.swift */, C4B5853B2770FE3900DA4FBE /* Paths.swift */, C4B5853C2770FE3900DA4FBE /* Shell.swift */, + C4C1019A27C65C6F001FACC2 /* Process.swift */, C40C7F2F27722E8D00DDDCDC /* Logger.swift */, C417DC73277614690015E6EE /* Helpers.swift */, ); @@ -420,7 +446,6 @@ children = ( C4F8C0A522D4FA41002EFE61 /* README.md */, C4E713562570150F00007428 /* SECURITY.md */, - C4F7807425D7F7E5000DBC97 /* RELEASE.md */, C4168F4427ADB4A3003B6C39 /* DEVELOPER.md */, C4E713572570151400007428 /* docs */, C41C1B3522B0097F00E7CF16 /* phpmon */, @@ -465,6 +490,7 @@ C41E181722CB61EB0072CF09 /* Domain */ = { isa = PBXGroup; children = ( + C4080FF827BD955900BF2C6B /* Notice */, C4AF9F6B275445D300D44ED0 /* Integrations */, C4B13B1D25C4915000548C3A /* App */, C4D9ADBD27761084007277F4 /* PHP */, @@ -513,10 +539,10 @@ isa = PBXGroup; children = ( C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */, - C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */, C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */, + C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */, C4CE3BB727B31F2E0086CA49 /* MainMenu+Switcher.swift */, - C4CE3BB927B31F670086CA49 /* MainMenu+Composer.swift */, + C42C49DA27C2806F0074ABAC /* MainMenu+FixMyValet.swift */, C47331A1247093B7009A0597 /* StatusMenu.swift */, C48D0C9525CC80B100CC7490 /* HeaderView.swift */, C48D0C9925CC888B00CC7490 /* HeaderView.xib */, @@ -538,7 +564,6 @@ C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */, C4CCBA6B275C567B008C7055 /* PMWindowController.swift */, C4B5635D276AB09000F12CCB /* VersionExtractor.swift */, - C4EC1E6C279DF87A0010F296 /* Async.swift */, ); path = Helpers; sourceTree = ""; @@ -556,6 +581,7 @@ isa = PBXGroup; children = ( C4AF9F792754499000D44ED0 /* Valet.swift */, + C4E4404527C56F4700D225E1 /* ValetSite.swift */, ); path = Valet; sourceTree = ""; @@ -589,8 +615,8 @@ C4811D2322D70A4700B5F6B3 /* App.swift */, C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */, C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */, - C4D8016522B1584700C6DA1B /* Startup.swift */, C4EED88827A48778006D7272 /* InterAppHandler.swift */, + C4D8016522B1584700C6DA1B /* Startup.swift */, ); path = App; sourceTree = ""; @@ -607,6 +633,35 @@ path = Common; sourceTree = ""; }; + C4C1019727C65A11001FACC2 /* Parsers */ = { + isa = PBXGroup; + children = ( + C4AF9F76275447F100D44ED0 /* ValetConfigParserTest.swift */, + C4F780AD25D80B37000DBC97 /* ExtensionParserTest.swift */, + C43A8A2325D9D20D00591B77 /* BrewJsonParserTest.swift */, + ); + path = Parsers; + sourceTree = ""; + }; + C4C1019827C65A1A001FACC2 /* Versions */ = { + isa = PBXGroup; + children = ( + C4FBFC512616485F00CDB8E1 /* PhpVersionDetectionTest.swift */, + C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */, + C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */, + C4AF9F7C275454A900D44ED0 /* ValetVersionExtractorTest.swift */, + ); + path = Versions; + sourceTree = ""; + }; + C4C1019927C65A4D001FACC2 /* Commands */ = { + isa = PBXGroup; + children = ( + C4F7809B25D80344000DBC97 /* CommandTest.swift */, + ); + path = Commands; + sourceTree = ""; + }; C4C8E81D276F5686003AC782 /* Watcher */ = { isa = PBXGroup; children = ( @@ -626,6 +681,7 @@ C4D89BC42783C98800A02B68 /* Composer */ = { isa = PBXGroup; children = ( + C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */, C4D89BC52783C99400A02B68 /* ComposerJson.swift */, C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */, ); @@ -673,16 +729,11 @@ isa = PBXGroup; children = ( C4F7807D25D7F84B000DBC97 /* Info.plist */, - C40C7F1C27720E1400DDDCDC /* Test Files */, - C4F7809B25D80344000DBC97 /* CommandTest.swift */, - C4F780AD25D80B37000DBC97 /* ExtensionParserTest.swift */, - C43A8A2325D9D20D00591B77 /* BrewJsonParserTest.swift */, - C4FBFC512616485F00CDB8E1 /* PhpVersionDetectionTest.swift */, - C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */, C43A8A1925D9CD1000591B77 /* Utility.swift */, - C4AF9F76275447F100D44ED0 /* ValetConfigParserTest.swift */, - C4AF9F7C275454A900D44ED0 /* ValetTest.swift */, - C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */, + C40C7F1C27720E1400DDDCDC /* Test Files */, + C4C1019927C65A4D001FACC2 /* Commands */, + C4C1019827C65A1A001FACC2 /* Versions */, + C4C1019727C65A11001FACC2 /* Parsers */, ); path = "phpmon-tests"; sourceTree = ""; @@ -694,6 +745,7 @@ C46FA23E246C358E00944F05 /* StringExtension.swift */, C48D0C9225CC804200CC7490 /* XibLoadable.swift */, C42759662627662800093CAE /* NSMenuExtension.swift */, + C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */, ); path = Extensions; sourceTree = ""; @@ -735,6 +787,9 @@ C4F7807F25D7F84B000DBC97 /* PBXTargetDependency */, ); name = "phpmon-tests"; + packageProductDependencies = ( + C4C1019527C659B7001FACC2 /* HotKey */, + ); productName = "phpmon-tests"; productReference = C4F7807925D7F84B000DBC97 /* phpmon-tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -754,7 +809,6 @@ }; C4F7807825D7F84B000DBC97 = { CreatedOnToolsVersion = 12.4; - TestTargetID = C41C1B3222B0097F00E7CF16; }; }; }; @@ -827,6 +881,7 @@ files = ( C4ACA38F25C754C100060C66 /* PhpExtension.swift in Sources */, C4D8016622B1584700C6DA1B /* Startup.swift in Sources */, + C42C49DB27C2806F0074ABAC /* MainMenu+FixMyValet.swift in Sources */, C48D6C70279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */, C4B585412770FE3900DA4FBE /* Shell.swift in Sources */, C4998F0A2617633900B2526E /* PrefsWC.swift in Sources */, @@ -835,10 +890,13 @@ 5420395926135DC100FB00FA /* PrefsVC.swift in Sources */, C43603A0275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */, C4068CA727B07A1300544CD5 /* SelectPreferenceView.swift in Sources */, + C4080FF627BD8C6400BF2C6B /* BetterAlert.swift in Sources */, + C4E0F7ED27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */, C49E171F27A5736E00787921 /* PMServicesView.swift in Sources */, C4EE55AD27708B9E001DF387 /* PMStatsView.swift in Sources */, C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, 54FCFD30276C8DA4004CE748 /* HotkeyPreferenceView.swift in Sources */, + C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */, C4EC1E68279DE0540010F296 /* ServicesView.swift in Sources */, C4F2E43A2752F7D00020E974 /* PhpInstallation.swift in Sources */, C41E871A2763D42300161EE0 /* SiteListVC+ContextMenu.swift in Sources */, @@ -875,8 +933,8 @@ C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */, C42759672627662800093CAE /* NSMenuExtension.swift in Sources */, C464ADAF275A7A69003FCD53 /* SiteListVC.swift in Sources */, - C4EC1E6D279DF87A0010F296 /* Async.swift in Sources */, C44CCD4927AFF3B700CE40E5 /* MainMenu+Async.swift in Sources */, + C4C1019B27C65C6F001FACC2 /* Process.swift in Sources */, C4EC1E73279DFCF40010F296 /* Events.swift in Sources */, C4927F0B27B2DFC200C55AFD /* Errors.swift in Sources */, C4B5853E2770FE3900DA4FBE /* Paths.swift in Sources */, @@ -889,8 +947,9 @@ C476FF9822B0DD830098105B /* Alert.swift in Sources */, C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */, C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */, - C4CE3BBA27B31F670086CA49 /* MainMenu+Composer.swift in Sources */, + C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */, C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */, + C4080FFA27BD956700BF2C6B /* BetterAlertVC.swift in Sources */, C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */, C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */, C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */, @@ -919,6 +978,7 @@ C4F780C825D80B75000DBC97 /* DateExtension.swift in Sources */, C493084B279F331F009C240B /* AddSiteVC.swift in Sources */, C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */, + C4080FFB27BD956700BF2C6B /* BetterAlertVC.swift in Sources */, C4F780CC25D80B75000DBC97 /* ActivePhpInstallation.swift in Sources */, C4F780B125D80B4D000DBC97 /* PhpExtension.swift in Sources */, C4068CA827B07A1300544CD5 /* SelectPreferenceView.swift in Sources */, @@ -931,10 +991,11 @@ C4F319C927B034A500AFF46F /* Stats.swift in Sources */, C4F30B04278E16BA00755FCE /* HomebrewService.swift in Sources */, C4AF9F7B2754499000D44ED0 /* Valet.swift in Sources */, + C4C1019C27C65C6F001FACC2 /* Process.swift in Sources */, C4F780C025D80B6E000DBC97 /* Startup.swift in Sources */, C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */, - C40B24F527A3108B0018C7D2 /* Async.swift in Sources */, C4B5635F276AB09000F12CCB /* VersionExtractor.swift in Sources */, + C4BF90C127C57C220054E78C /* MainMenu+FixMyValet.swift in Sources */, C4F2E4382752F08D0020E974 /* HomebrewDiagnostics.swift in Sources */, C4F780AE25D80B37000DBC97 /* ExtensionParserTest.swift in Sources */, C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, @@ -952,9 +1013,10 @@ C464ADB3275A87CA003FCD53 /* SiteListCell.swift in Sources */, C415D3E92770F692005EF286 /* AppDelegate+InterApp.swift in Sources */, C4AF9F78275447F100D44ED0 /* ValetConfigParserTest.swift in Sources */, - C4CE3BBC27B324250086CA49 /* MainMenu+Composer.swift in Sources */, + C4CE3BBC27B324250086CA49 /* ComposerWindow.swift in Sources */, C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */, C417DC75277614690015E6EE /* Helpers.swift in Sources */, + C4080FF727BD8C6400BF2C6B /* BetterAlert.swift in Sources */, C4B97B7C275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */, C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */, C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */, @@ -972,18 +1034,20 @@ C4F30B0B278E203C00755FCE /* MainMenu+Startup.swift in Sources */, C40B24F227A310770018C7D2 /* Events.swift in Sources */, C4F30B0A278E1A1A00755FCE /* ComposerJson.swift in Sources */, - C4AF9F7D275454A900D44ED0 /* ValetTest.swift in Sources */, + C4AF9F7D275454A900D44ED0 /* ValetVersionExtractorTest.swift in Sources */, C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */, C4B585452770FE3900DA4FBE /* Command.swift in Sources */, C40B24F127A3106D0018C7D2 /* ServicesView.swift in Sources */, C4F780C525D80B75000DBC97 /* MenuBarImageGenerator.swift in Sources */, C4F780B725D80B5D000DBC97 /* App.swift in Sources */, C4927F0C27B2DFC200C55AFD /* Errors.swift in Sources */, + C4E4404727C56F4700D225E1 /* ValetSite.swift in Sources */, C44CCD4A27AFF3BC00CE40E5 /* MainMenu+Async.swift in Sources */, C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */, C4F780C925D80B75000DBC97 /* StringExtension.swift in Sources */, C4B5853F2770FE3900DA4FBE /* Paths.swift in Sources */, C481F79A26164A7C004FBCFF /* Preferences.swift in Sources */, + C4E0F7EE27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */, C4B585422770FE3900DA4FBE /* Shell.swift in Sources */, C464ADAD275A7A3F003FCD53 /* SiteListWC.swift in Sources */, C40C7F1F2772136000DDDCDC /* PhpEnv.swift in Sources */, @@ -1143,7 +1207,8 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 610; + CURRENT_PROJECT_VERSION = 715; + DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = phpmon/Info.plist; @@ -1152,7 +1217,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 5.0.1; + MARKETING_VERSION = 5.1; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1168,7 +1233,8 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 610; + CURRENT_PROJECT_VERSION = 715; + DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = phpmon/Info.plist; @@ -1177,7 +1243,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 5.0.1; + MARKETING_VERSION = 5.1; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1188,7 +1254,6 @@ C4F7808125D7F84B000DBC97 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -1202,14 +1267,12 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PHP Monitor.app/Contents/MacOS/PHP Monitor"; }; name = Debug; }; C4F7808225D7F84B000DBC97 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -1223,7 +1286,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.nicoverbruggen.phpmon-tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PHP Monitor.app/Contents/MacOS/PHP Monitor"; }; name = Release; }; @@ -1276,6 +1338,11 @@ package = C4998F0426175E7200B2526E /* XCRemoteSwiftPackageReference "HotKey" */; productName = HotKey; }; + C4C1019527C659B7001FACC2 /* HotKey */ = { + isa = XCSwiftPackageProductDependency; + package = C4998F0426175E7200B2526E /* XCRemoteSwiftPackageReference "HotKey" */; + productName = HotKey; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = C41C1B2B22B0097F00E7CF16 /* Project object */; diff --git a/README.md b/README.md index 8e4025e..4b1caeb 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,13 @@ To upgrade your existing installation, run: brew upgrade phpmon -(You may need to run `brew update` first in order to update the cask file if you ran a Homebrew operation recently.) +(You may need to run `brew update` or `brew update-reset` first in order to update the cask file if you ran a Homebrew operation recently.) + +## ⚡️ Launchers (Alfred, Raycast) + +If you would like to integrate with your launcher of choice, you can also download an [Alfred workflow](https://github.com/nicoverbruggen/phpmon/raw/main/integrations/phpmon.alfredworkflow) or [Raycast extension](https://www.raycast.com/nicoverbruggen/php-monitor) that works with PHP Monitor. + +The app must be running in the background for these to work, and the _Allow third-party integrations_ checkbox must be enabled in Preferences (it is by default). ## 🔑 Is the app signed & notarized? @@ -231,8 +237,15 @@ Since v3.4 all of the loaded .ini files are sourced to determine which extension
I've got two Homebrew installations on my Apple Silicon Mac, can I choose which installation to use with PHP Monitor? -Not at this time, no. PHP Monitor will prefer the `/opt/homebrew` installation over the classic installation directory. +If you are using PHP Monitor on an Intel machine or on an Apple Silicon machine with Rosetta enabled, PHP Monitor expects the main Homebrew binary in `/usr/local/bin/brew`. +If you are using PHP Monitor on Apple Silicon without Rosetta, PHP Monitor expects the main Homebrew binary in `/opt/homebrew/bin/brew`. + +If there's an issue here, you'll get an alert at launch. + +Make sure that the version of Homebrew that you are running normally is the same as the one that PHP Monitor expects. If you are on M1 hardware for example, but still using Rosetta for Homebrew, you'll need to run PHP Monitor under Rosetta as well. + +PHP Monitor is a universal app and supports both architectures, so [find out here](https://support.apple.com/en-us/HT211861) how to enable Rosetta with PHP Monitor.
@@ -267,9 +280,11 @@ You can put as many apps as you'd like in the `scan_apps` array, and PHP Monitor
-How can the app integrate with third party tools, like Alfred? +How can the app integrate with third party tools, like Alfred or Raycast? -There's an Alfred workflow usually included in the release list, you can grab it by going to releases and downloading the asset `phpmon.alfredworkflow`. +PHP Monitor supports third party app integrations by default, and this feature is enabled in Preferences unless you disable it. + +You can grab the official [Alfred workflow](https://github.com/nicoverbruggen/phpmon/raw/main/integrations/phpmon.alfredworkflow) or [Raycast extension](https://www.raycast.com/nicoverbruggen/php-monitor). If you'd like to integrate something yourself, all you need to to is use the `phpmon://` protocol and ensure that third party app integrations are enabled in Preferences (in PHP Monitor). diff --git a/RELEASE.md b/RELEASE.md deleted file mode 100644 index 6db49da..0000000 --- a/RELEASE.md +++ /dev/null @@ -1,13 +0,0 @@ -# Release Procedure - -1. Merge into `main` -2. Create tag -3. Add changes to changelog + update security document -4. Archive -5. Notarize and prepare for own distribution -6. After notarization, export .app -7. Create zipped version -8. Calculate SHA256: `openssl dgst -sha256 phpmon.zip` -9. Upload to GitHub and add to tagged release -10. Update Cask with new version + hash -11. Check new version can be installed via Cask diff --git a/SECURITY.md b/SECURITY.md index 67dfa51..be6bec2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,7 +6,7 @@ Generally speaking, only the latest version of **PHP Monitor** is supported, exc | Version | Apple Silicon | Supported | Supported macOS | Deployment Target | Detected PHP Versions | Minimum Required Valet Version | | ------- | ------------- | ------------------ | ----- | ----- | ----- | ---- -| 5.0 | ✅ Universal binary | ✅ Yes | Big Sur (11.0) and Monterey (12.0) | macOS 11+ | PHP 5.6—PHP 8.2 | 2.16.2 | +| 5 | ✅ Universal binary | ✅ Yes | Big Sur (11.0) and Monterey (12.0) | macOS 11+ | PHP 5.6—PHP 8.2 | 2.16.2 | ## Legacy versions diff --git a/assets/affinity/icon.afdesign b/assets/affinity/icon.afdesign new file mode 100644 index 0000000..e5b3710 Binary files /dev/null and b/assets/affinity/icon.afdesign differ diff --git a/assets/icons.afdesign b/assets/affinity/icons.afdesign similarity index 100% rename from assets/icons.afdesign rename to assets/affinity/icons.afdesign diff --git a/phpmon-tests/CommandTest.swift b/phpmon-tests/Commands/CommandTest.swift similarity index 100% rename from phpmon-tests/CommandTest.swift rename to phpmon-tests/Commands/CommandTest.swift diff --git a/phpmon-tests/BrewJsonParserTest.swift b/phpmon-tests/Parsers/BrewJsonParserTest.swift similarity index 100% rename from phpmon-tests/BrewJsonParserTest.swift rename to phpmon-tests/Parsers/BrewJsonParserTest.swift diff --git a/phpmon-tests/ExtensionParserTest.swift b/phpmon-tests/Parsers/ExtensionParserTest.swift similarity index 100% rename from phpmon-tests/ExtensionParserTest.swift rename to phpmon-tests/Parsers/ExtensionParserTest.swift diff --git a/phpmon-tests/ValetConfigParserTest.swift b/phpmon-tests/Parsers/ValetConfigParserTest.swift similarity index 100% rename from phpmon-tests/ValetConfigParserTest.swift rename to phpmon-tests/Parsers/ValetConfigParserTest.swift diff --git a/phpmon-tests/PhpVersionDetectionTest.swift b/phpmon-tests/Versions/PhpVersionDetectionTest.swift similarity index 100% rename from phpmon-tests/PhpVersionDetectionTest.swift rename to phpmon-tests/Versions/PhpVersionDetectionTest.swift diff --git a/phpmon-tests/PhpVersionNumberTest.swift b/phpmon-tests/Versions/PhpVersionNumberTest.swift similarity index 100% rename from phpmon-tests/PhpVersionNumberTest.swift rename to phpmon-tests/Versions/PhpVersionNumberTest.swift diff --git a/phpmon-tests/ValetTest.swift b/phpmon-tests/Versions/ValetVersionExtractorTest.swift similarity index 73% rename from phpmon-tests/ValetTest.swift rename to phpmon-tests/Versions/ValetVersionExtractorTest.swift index b7713c4..8d7ceb6 100644 --- a/phpmon-tests/ValetTest.swift +++ b/phpmon-tests/Versions/ValetVersionExtractorTest.swift @@ -8,10 +8,10 @@ import XCTest -class ValetTest: XCTestCase { +class ValetVersionExtractorTest: XCTestCase { func testDetermineValetVersion() { - let version = valet("--version") + let version = valet("--version", sudo: false) XCTAssert(version.contains("Laravel Valet 2.")) } diff --git a/phpmon-tests/VersionExtractorTest.swift b/phpmon-tests/Versions/VersionExtractorTest.swift similarity index 100% rename from phpmon-tests/VersionExtractorTest.swift rename to phpmon-tests/Versions/VersionExtractorTest.swift diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_128x128.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_128x128.png deleted file mode 100644 index 67950a5..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_128x128.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_128x128@2x.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_128x128@2x.png deleted file mode 100644 index bca82db..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_128x128@2x.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_16x16.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_16x16.png deleted file mode 100644 index f0eb45e..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_16x16.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_16x16@2x.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_16x16@2x.png deleted file mode 100644 index 7727960..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_16x16@2x.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_256x256.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_256x256.png deleted file mode 100644 index bca82db..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_256x256.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_256x256@2x.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_256x256@2x.png deleted file mode 100644 index 3c25ee2..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_256x256@2x.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_32x32.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_32x32.png deleted file mode 100644 index 7727960..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_32x32.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_32x32@2x.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_32x32@2x.png deleted file mode 100644 index 4708c68..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_32x32@2x.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_512x512.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_512x512.png deleted file mode 100644 index 3c25ee2..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_512x512.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_512x512@2x.png b/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_512x512@2x.png deleted file mode 100644 index ade05f1..0000000 Binary files a/phpmon/Assets.xcassets/AppIconBeta.appiconset/icon_512x512@2x.png and /dev/null differ diff --git a/phpmon/Assets.xcassets/AppIconBeta.appiconset/Contents.json b/phpmon/Assets.xcassets/AppIconDev.appiconset/Contents.json similarity index 100% rename from phpmon/Assets.xcassets/AppIconBeta.appiconset/Contents.json rename to phpmon/Assets.xcassets/AppIconDev.appiconset/Contents.json diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_128x128.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_128x128.png new file mode 100644 index 0000000..8cace12 Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_128x128.png differ diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_128x128@2x.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_128x128@2x.png new file mode 100644 index 0000000..c9efdb2 Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_128x128@2x.png differ diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_16x16.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_16x16.png new file mode 100644 index 0000000..5e266f6 Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_16x16.png differ diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_16x16@2x.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_16x16@2x.png new file mode 100644 index 0000000..426a9bf Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_16x16@2x.png differ diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_256x256.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_256x256.png new file mode 100644 index 0000000..c9efdb2 Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_256x256.png differ diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_256x256@2x.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_256x256@2x.png new file mode 100644 index 0000000..e09b602 Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_256x256@2x.png differ diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_32x32.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_32x32.png new file mode 100644 index 0000000..426a9bf Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_32x32.png differ diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_32x32@2x.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_32x32@2x.png new file mode 100644 index 0000000..9c94515 Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_32x32@2x.png differ diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_512x512.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_512x512.png new file mode 100644 index 0000000..e09b602 Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_512x512.png differ diff --git a/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_512x512@2x.png b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_512x512@2x.png new file mode 100644 index 0000000..c178918 Binary files /dev/null and b/phpmon/Assets.xcassets/AppIconDev.appiconset/icon_512x512@2x.png differ diff --git a/phpmon/Common/Core/Actions.swift b/phpmon/Common/Core/Actions.swift index 23a677b..8346655 100644 --- a/phpmon/Common/Core/Actions.swift +++ b/phpmon/Common/Core/Actions.swift @@ -116,6 +116,8 @@ class Actions { Detects all currently available PHP versions, and unlinks each and every one of them. + This all happens in sequence, nothing runs in parallel. + After this, the brew services are also stopped, the latest PHP version is linked, and php + nginx are restarted. diff --git a/phpmon/Common/Core/Constants.swift b/phpmon/Common/Core/Constants.swift index 1c67126..85c6e2e 100644 --- a/phpmon/Common/Core/Constants.swift +++ b/phpmon/Common/Core/Constants.swift @@ -7,7 +7,7 @@ import Cocoa -class Constants { +struct Constants { /** * The latest PHP version that is considered to be stable at the time of release. @@ -50,10 +50,19 @@ class Constants { // dev release. In this case, that means that the version below is detected. "8.2" ] - - /** - The URL that people can visit if they wish to help support the project. - */ - static let DonationUrl = URL(string: "https://nicoverbruggen.be/sponsor#pay-now")! + + struct Urls { + + static let DonationPayment = URL( + string: "https://nicoverbruggen.be/sponsor#pay-now" + )! + static let DonationPage = URL( + string: "https://nicoverbruggen.be/sponsor" + )! + static let FrequentlyAskedQuestions = URL( + string: "https://github.com/nicoverbruggen/phpmon#%EF%B8%8F-faq--troubleshooting" + )! + + } } diff --git a/phpmon/Common/Core/Helpers.swift b/phpmon/Common/Core/Helpers.swift index 369b605..da1f439 100644 --- a/phpmon/Common/Core/Helpers.swift +++ b/phpmon/Common/Core/Helpers.swift @@ -9,11 +9,11 @@ // MARK: Common Shell Commands /** - Runs a `valet` command. + Runs a `valet` command. Defaults to running as superuser. */ -func valet(_ command: String) -> String +func valet(_ command: String, sudo: Bool = true) -> String { - return Shell.pipe("sudo \(Paths.valet) \(command)", requiresPath: true) + return Shell.pipe("\(sudo ? "sudo " : "")" + "\(Paths.valet) \(command)", requiresPath: true) } /** @@ -35,7 +35,7 @@ func sed(file: String, original: String, replacement: String) // Check if gsed exists; it is able to follow symlinks, // which we want to do to toggle the extension - if Shell.fileExists("\(Paths.binPath)/gsed") { + if Filesystem.fileExists("\(Paths.binPath)/gsed") { Shell.run("\(Paths.binPath)/gsed -i --follow-symlinks 's/\(e_original)/\(e_replacement)/g' \(file)") } else { Shell.run("sed -i '' 's/\(e_original)/\(e_replacement)/g' \(file)") diff --git a/phpmon/Common/Core/Logger.swift b/phpmon/Common/Core/Logger.swift index 8616528..d963558 100644 --- a/phpmon/Common/Core/Logger.swift +++ b/phpmon/Common/Core/Logger.swift @@ -27,25 +27,31 @@ class Log { static func err(_ item: Any) { if Verbosity.error.isApplicable() { - print("[ERR] \(item)") + print("[E] \(item)") } } static func warn(_ item: Any) { if Verbosity.warning.isApplicable() { - print("[WRN] \(item)") + print("[W] \(item)") } } static func info(_ item: Any) { if Verbosity.info.isApplicable() { - print(item) + print("\(item)") } } static func perf(_ item: Any) { if Verbosity.performance.isApplicable() { - print(item) + print("[P] \(item)") + } + } + + static func separator(as verbosity: Verbosity = .info) { + if verbosity.isApplicable() { + print("==================================") } } diff --git a/phpmon/Common/Core/Paths.swift b/phpmon/Common/Core/Paths.swift index a227cc3..4c4dfe9 100644 --- a/phpmon/Common/Core/Paths.swift +++ b/phpmon/Common/Core/Paths.swift @@ -15,15 +15,19 @@ public class Paths { public static let shared = Paths() - private var baseDir : Paths.HomebrewDir + internal var baseDir: Paths.HomebrewDir - private var userName : String + private var userName: String init() { - baseDir = FileManager.default.fileExists(atPath: "\(HomebrewDir.opt.rawValue)/bin/brew") ? .opt : .usr + baseDir = App.architecture != "x86_64" ? .opt : .usr userName = String(Shell.pipe("whoami").split(separator: "\n")[0]) } + public func detectBinaryPaths() { + detectComposerBinary() + } + // - MARK: Binaries public static var valet: String { @@ -42,6 +46,11 @@ public class Paths { return "\(binPath)/php-config" } + // - MARK: Detected Binaries + + /** The path to the Composer binary. Can be in multiple locations, so is detected instead. */ + public static var composer: String? = nil + // - MARK: Paths public static var whoami: String { @@ -64,6 +73,21 @@ public class Paths { return "\(shared.baseDir.rawValue)/etc" } + // MARK: - Flexible Binaries + // (these can be in multiple locations, so we scan common places because) + // (PHP Monitor will not use the user's own PATH) + + private func detectComposerBinary() { + if Filesystem.fileExists("/usr/local/bin/composer") { + Paths.composer = "/usr/local/bin/composer" + } else if Filesystem.fileExists("/opt/homebrew/bin/composer") { + Paths.composer = "/opt/homebrew/bin/composer" + } else { + Paths.composer = nil + Log.warn("Composer was not found.") + } + } + // MARK: - Enum public enum HomebrewDir: String { diff --git a/phpmon/Common/Core/Process.swift b/phpmon/Common/Core/Process.swift new file mode 100644 index 0000000..48c7543 --- /dev/null +++ b/phpmon/Common/Core/Process.swift @@ -0,0 +1,59 @@ +// +// Process.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 23/02/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Foundation + +extension Process { + + /** + When a process is running in the background, it can send content to standard + output or standard error, just like it would in a terminal. Using `listen` + allows us to react whenever data is received by running a particular closure, + depending on which type of data is received. + */ + public func listen( + didReceiveStandardOutputData: @escaping (String) -> Void, + didReceiveStandardErrorData: @escaping (String) -> Void + ) { + let outputPipe = Pipe() + let errorPipe = Pipe() + + self.standardOutput = outputPipe + self.standardError = errorPipe + + [ + (outputPipe, didReceiveStandardOutputData), + (errorPipe, didReceiveStandardErrorData) + ].forEach { (pipe: Pipe, callback: @escaping (String) -> Void) in + pipe.fileHandleForReading.waitForDataInBackgroundAndNotify() + NotificationCenter.default.addObserver( + forName: NSNotification.Name.NSFileHandleDataAvailable, + object: pipe.fileHandleForReading, + queue: nil + ) { notification in + if let outputString = String(data: pipe.fileHandleForReading.availableData, encoding: String.Encoding.utf8) { + callback(outputString) + } + pipe.fileHandleForReading.waitForDataInBackgroundAndNotify() + } + } + } + + /** + After the process is done running, you'll want to stop listening. + */ + public func haltListening() { + if let pipe = self.standardOutput as? Pipe { + NotificationCenter.default.removeObserver(pipe.fileHandleForReading) + } + if let pipe = self.standardError as? Pipe { + NotificationCenter.default.removeObserver(pipe.fileHandleForReading) + } + } + +} diff --git a/phpmon/Common/Core/Shell.swift b/phpmon/Common/Core/Shell.swift index 8ea3e2e..b225fb9 100644 --- a/phpmon/Common/Core/Shell.swift +++ b/phpmon/Common/Core/Shell.swift @@ -104,15 +104,6 @@ public class Shell { ) } - /** - Checks if a file exists at a certain path. - Used to be done with a shell command, now uses the native FileManager class instead. - */ - public static func fileExists(_ path: String) -> Bool { - let fullPath = path.replacingOccurrences(of: "~", with: "/Users/\(Paths.whoami)") - return FileManager.default.fileExists(atPath: fullPath) - } - /** Creates a new process with the correct PATH and shell. */ @@ -128,42 +119,6 @@ public class Shell { return task } - public static func captureOutput( - _ task: Process, - didReceiveStdOutData: @escaping (String) -> Void, - didReceiveStdErrData: @escaping (String) -> Void - ) { - let outputPipe = Pipe() - let errorPipe = Pipe() - - task.standardOutput = outputPipe - task.standardError = errorPipe - - [(outputPipe, didReceiveStdOutData), (errorPipe, didReceiveStdErrData)].forEach { - (pipe: Pipe, callback: @escaping (String) -> Void) in - pipe.fileHandleForReading.waitForDataInBackgroundAndNotify() - NotificationCenter.default.addObserver( - forName: NSNotification.Name.NSFileHandleDataAvailable, - object: pipe.fileHandleForReading, - queue: nil - ) { notification in - if let outputString = String(data: pipe.fileHandleForReading.availableData, encoding: String.Encoding.utf8) { - callback(outputString) - } - pipe.fileHandleForReading.waitForDataInBackgroundAndNotify() - } - } - } - - public static func haltCapturingOutput(_ task: Process) { - if let pipe = task.standardOutput as? Pipe { - NotificationCenter.default.removeObserver(pipe.fileHandleForReading) - } - if let pipe = task.standardError as? Pipe { - NotificationCenter.default.removeObserver(pipe.fileHandleForReading) - } - } - public class Output { public let standardOutput: String public let errorOutput: String diff --git a/phpmon/Common/Extensions/NSWindowExtension.swift b/phpmon/Common/Extensions/NSWindowExtension.swift new file mode 100644 index 0000000..21f8b03 --- /dev/null +++ b/phpmon/Common/Extensions/NSWindowExtension.swift @@ -0,0 +1,38 @@ +// +// NSWindowExtension.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 17/02/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Foundation +import Cocoa + +extension NSWindow { + + /** + Shakes a window. Inspired by: http://blog.ericd.net/2016/09/30/shaking-a-macos-window/ + */ + func shake(){ + let numberOfShakes = 3, durationOfShake = 0.2, vigourOfShake: CGFloat = 0.03 + + let frame: CGRect = self.frame + let shakeAnimation :CAKeyframeAnimation = CAKeyframeAnimation() + + let shakePath = CGMutablePath() + shakePath.move( to: CGPoint(x:NSMinX(frame), y:NSMinY(frame))) + + for _ in 0...numberOfShakes-1 { + shakePath.addLine(to: CGPoint(x:NSMinX(frame) - frame.size.width * vigourOfShake, y:NSMinY(frame))) + shakePath.addLine(to: CGPoint(x:NSMinX(frame) + frame.size.width * vigourOfShake, y:NSMinY(frame))) + } + + shakePath.closeSubpath() + shakeAnimation.path = shakePath + shakeAnimation.duration = durationOfShake + + self.animations = ["frameOrigin":shakeAnimation] + self.animator().setFrameOrigin(self.frame.origin) + } +} diff --git a/phpmon/Common/Helpers/Alert.swift b/phpmon/Common/Helpers/Alert.swift index 25327a7..400c257 100644 --- a/phpmon/Common/Helpers/Alert.swift +++ b/phpmon/Common/Helpers/Alert.swift @@ -9,24 +9,6 @@ import Cocoa class Alert { - public static func present( - messageText: String, - informativeText: String, - buttonTitle: String = "OK", - secondButtonTitle: String = "", - style: NSAlert.Style = .informational - ) -> Bool { - let alert = NSAlert.init() - alert.alertStyle = style - alert.messageText = messageText - alert.informativeText = informativeText - alert.addButton(withTitle: buttonTitle) - if (!secondButtonTitle.isEmpty) { - alert.addButton(withTitle: secondButtonTitle) - } - return alert.runModal() == .alertFirstButtonReturn - } - public static func confirm( onWindow window: NSWindow, messageText: String, @@ -36,6 +18,10 @@ class Alert { style: NSAlert.Style = .warning, onFirstButtonPressed: @escaping (() -> Void) ) { + if !Thread.isMainThread { + fatalError("You should always present alerts on the main thread!") + } + let alert = NSAlert.init() alert.alertStyle = style alert.messageText = messageText @@ -51,31 +37,4 @@ class Alert { } } - /** - Notify the user about something by showing an alert. - */ - public static func notify(message: String, info: String, style: NSAlert.Style = .informational) { - _ = present( - messageText: message, - informativeText: info, - buttonTitle: "OK", - secondButtonTitle: "", - style: style - ) - } - - /** - Notify the user about a particular error (which must be `Alertable`) - by showing an alert. - */ - public static func notify(about error: Error & AlertableError) { - let key = error.getErrorMessageKey() - _ = present( - messageText: "\(key).title".localized, - informativeText: "\(key).description".localized, - buttonTitle: "OK", - secondButtonTitle: "", - style: .critical - ) - } } diff --git a/phpmon/Common/Helpers/Async.swift b/phpmon/Common/Helpers/Async.swift deleted file mode 100644 index 515c805..0000000 --- a/phpmon/Common/Helpers/Async.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// Async.swift -// PHP Monitor -// -// Created by Nico Verbruggen on 23/01/2022. -// Copyright © 2022 Nico Verbruggen. All rights reserved. -// - -import Foundation - -/** - This generic async helper is something I'd like to use in more places. - - The `DispatchQueue.global` into `DispatchQueue.main.async` logic is common in the app. - - I could also use try `async` support which was introduced in Swift but that would - require too much refactoring at this time to consider. I also need to read up on async - in order to properly grasp all the gotchas. Looking into that later at some point. - */ -public func runAsync(_ execute: @escaping () -> Void, completion: @escaping () -> Void = {}) -{ - DispatchQueue.global(qos: .userInitiated).async { - execute() - - DispatchQueue.main.async { - completion() - } - } -} diff --git a/phpmon/Common/PHP/ActivePhpInstallation.swift b/phpmon/Common/PHP/ActivePhpInstallation.swift index f4b124e..6ea858f 100644 --- a/phpmon/Common/PHP/ActivePhpInstallation.swift +++ b/phpmon/Common/PHP/ActivePhpInstallation.swift @@ -137,7 +137,7 @@ class ActivePhpInstallation { } // Make sure to check if valet-fpm.conf exists. If it does, we should be fine :) - return Shell.fileExists("\(Paths.etcPath)/php/\(self.version.short)/php-fpm.d/valet-fpm.conf") + return Filesystem.fileExists("\(Paths.etcPath)/php/\(self.version.short)/php-fpm.d/valet-fpm.conf") } // MARK: - Structs diff --git a/phpmon/Common/PHP/Homebrew/HomebrewService.swift b/phpmon/Common/PHP/Homebrew/HomebrewService.swift index 6c21af4..75c1d84 100644 --- a/phpmon/Common/PHP/Homebrew/HomebrewService.swift +++ b/phpmon/Common/PHP/Homebrew/HomebrewService.swift @@ -18,4 +18,18 @@ struct HomebrewService: Decodable, Equatable { let status: String? let log_path: String? let error_log_path: String? + + public static func loadAll( + filter: [String] = [PhpEnv.phpInstall.formula, "nginx", "dnsmasq"] + ) async -> [HomebrewService] { + return try! JSONDecoder().decode( + [HomebrewService].self, + from: Shell.pipe( + "sudo \(Paths.brew) services info --all --json", + requiresPath: true + ).data(using: .utf8)! + ).filter({ service in + return filter.contains(service.name) + }) + } } diff --git a/phpmon/Common/PHP/PHP Version/PhpEnv.swift b/phpmon/Common/PHP/PHP Version/PhpEnv.swift index 04230e2..571b762 100644 --- a/phpmon/Common/PHP/PHP Version/PhpEnv.swift +++ b/phpmon/Common/PHP/PHP Version/PhpEnv.swift @@ -95,7 +95,7 @@ class PhpEnv { let phpAlias = homebrewPackage.version // Avoid inserting a duplicate - if (!versionsOnly.contains(phpAlias) && Shell.fileExists("\(Paths.optPath)/php/bin/php")) { + if (!versionsOnly.contains(phpAlias) && Filesystem.fileExists("\(Paths.optPath)/php/bin/php")) { versionsOnly.append(phpAlias) } @@ -134,7 +134,7 @@ class PhpEnv { // is supported and where the binary exists (avoids broken installs) if !output.contains(version) && Constants.SupportedPhpVersions.contains(version) - && (checkBinaries ? Shell.fileExists("\(Paths.optPath)/php@\(version)/bin/php") : true) + && (checkBinaries ? Filesystem.fileExists("\(Paths.optPath)/php@\(version)/bin/php") : true) { output.append(version) } diff --git a/phpmon/Common/PHP/PHP Version/PhpVersionNumber.swift b/phpmon/Common/PHP/PHP Version/PhpVersionNumber.swift index 5f4c352..1461df6 100644 --- a/phpmon/Common/PHP/PHP Version/PhpVersionNumber.swift +++ b/phpmon/Common/PHP/PHP Version/PhpVersionNumber.swift @@ -96,6 +96,12 @@ public struct PhpVersionNumber: Equatable { let minor: Int let patch: Int? + public func toString() -> String { + return self.patch == nil + ? "\(major).\(minor)" + : "\(major).\(minor).\(patch!)" + } + public func patch(_ strictFallback: Bool = true, _ constraint: PhpVersionNumber? = nil) -> Int { return patch ?? (strictFallback ? 0 : constraint?.patch ?? 999) } @@ -111,7 +117,7 @@ public struct PhpVersionNumber: Equatable { case greaterThanOrEqual = #"^>=(?\d+).(?\d+).?(?\d+)?\z"# case greaterThan = #"^>(?\d+).(?\d+).?(?\d+)?\z"# - // TODO: (5.1) Handle these cases (even though I suspect these are uncommon) + // TODO: (6.0) Handle these cases (even though I suspect these are uncommon) /* case smallerThanOrEqual = #"^<=(?\d+).(?\d+).?(?\d+)?\z"# case smallerThan = #"^<(?\d+).(?\d+).?(?\d+)?\z"# diff --git a/phpmon/Common/PHP/PhpInstallation.swift b/phpmon/Common/PHP/PhpInstallation.swift index f36fde1..ba2682e 100644 --- a/phpmon/Common/PHP/PhpInstallation.swift +++ b/phpmon/Common/PHP/PhpInstallation.swift @@ -21,7 +21,7 @@ class PhpInstallation { let phpConfigExecutablePath = "\(Paths.optPath)/php@\(version)/bin/php-config" self.longVersion = PhpVersionNumber.make(from: version)! - if Shell.fileExists(phpConfigExecutablePath) { + if Filesystem.fileExists(phpConfigExecutablePath) { let longVersionString = Command.execute( path: phpConfigExecutablePath, arguments: ["--version"] @@ -29,7 +29,6 @@ class PhpInstallation { // The parser should always work, or the string has to be very unusual. // If so, the app SHOULD crash, so that the users report what's up. - // TODO: Alert the user that the version number could not be parsed. self.longVersion = try! PhpVersionNumber.parse(longVersionString) } } diff --git a/phpmon/Common/PHP/Switcher/PhpSwitcher.swift b/phpmon/Common/PHP/Switcher/PhpSwitcher.swift index 324bcde..86856e1 100644 --- a/phpmon/Common/PHP/Switcher/PhpSwitcher.swift +++ b/phpmon/Common/PHP/Switcher/PhpSwitcher.swift @@ -10,9 +10,9 @@ import Foundation protocol PhpSwitcherDelegate: AnyObject { - func switcherDidStartSwitching(to: String) + func switcherDidStartSwitching(to version: String) - func switcherDidCompleteSwitch(to: String) + func switcherDidCompleteSwitch(to version: String) } diff --git a/phpmon/Domain/App/App.swift b/phpmon/Domain/App/App.swift index ae76d89..857b9a9 100644 --- a/phpmon/Domain/App/App.swift +++ b/phpmon/Domain/App/App.swift @@ -22,9 +22,18 @@ class App { return "\(version) (\(build))" } - /** Whether the app is busy doing something. Used to determine what UI to display. */ - static var busy: Bool { - return PhpEnv.shared.isBusy + static var architecture: String { + var systeminfo = utsname() + uname(&systeminfo) + let machine = withUnsafeBytes(of: &systeminfo.machine) {bufPtr->String in + let data = Data(bufPtr) + if let lastIndex = data.lastIndex(where: {$0 != 0}) { + return String(data: data[0...lastIndex], encoding: .isoLatin1)! + } else { + return String(data: data, encoding: .isoLatin1)! + } + } + return machine } // MARK: Variables diff --git a/phpmon/Domain/App/AppDelegate.swift b/phpmon/Domain/App/AppDelegate.swift index fbca312..a0e1f74 100644 --- a/phpmon/Domain/App/AppDelegate.swift +++ b/phpmon/Domain/App/AppDelegate.swift @@ -64,10 +64,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele */ override init() { logger.verbosity = .info - Log.info("==================================") + #if DEBUG + logger.verbosity = .performance + #endif + Log.separator(as: .info) Log.info("PHP MONITOR by Nico Verbruggen") Log.info("Version \(App.version)") - Log.info("==================================") + Log.separator(as: .info) self.sharedShell = Shell.user self.state = App.shared self.menu = MainMenu.shared @@ -91,7 +94,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele // Make sure notifications will work setupNotifications() // Make sure the menu performs its initial checks - menu.startup() + Task { await menu.startup() } } } diff --git a/phpmon/Domain/App/Base.lproj/Main.storyboard b/phpmon/Domain/App/Base.lproj/Main.storyboard index bebb3da..b0521c5 100644 --- a/phpmon/Domain/App/Base.lproj/Main.storyboard +++ b/phpmon/Domain/App/Base.lproj/Main.storyboard @@ -462,7 +462,177 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sometimes you need a really long explanation and in that case you can get a really, really long description here, along with, for example, various steps you can take. This allows for a lot of text to be displayed, yay! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -472,8 +642,16 @@ + + + + + + + +