diff --git a/DEVELOPER.md b/DEVELOPER.md new file mode 100644 index 0000000..f06f564 --- /dev/null +++ b/DEVELOPER.md @@ -0,0 +1,46 @@ +# DEVELOPER README + +## 🔧 Build instructions + +build button in Xcode + +If you'd like to build PHP Monitor yourself, you need: + +* Xcode (usually the latest version) +* The contents of this repository + +Once you have downloaded this repository, open `PHP Monitor.xcodeproj`, and you should be able to immediately build the app for your system by pressing Cmd-R. This will create a debug build. (If Xcode complains about code signing, you can turn it off.) + +If you'd like to create a production build, choose "Any Mac" as the target and select Product > Archive. + +## 🐛 Symbolication of crashes + +If you have an archived build of the app and exported the DSYM, it is possible to symbolicate .ips crash logs. + +For example, given the following crash (from an .ips file): + +``` +Thread 2 Crashed:: Dispatch queue: com.apple.root.user-initiated-qos +0 libswiftDispatch.dylib 0x7ff82aa3ab8c static OS_dispatch_source.makeProcessSource(identifier:eventMask:queue:) + 28 +1 PHP Monitor 0x1096907d8 0x10965e000 + 206808 + | | + address load address +2 PHP Monitor 0x1096903ac 0x10965e000 + 205740 +3 PHP Monitor 0x10968f88b 0x10965e000 + 202891 +``` + +You must use the correct order for the the address and load address in the command below: + +``` +$ atos -arch x86_64 -o '/path/to/PHP Monitor.app.dSYM/Contents/Resources/DWARF/PHP Monitor' -l 0x10965e000 0x1096907d8 + | | | | + architecture path to DSYM load address address +``` + +This will return the relevant information, for example: + +``` +FSWatcher.startMonitoring(_:behaviour:) (in PHP Monitor) (PhpConfigWatcher.swift:95) +``` + +For more information, see [Apple's documentation](https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report). diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 0c151ef..01baff1 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -9,13 +9,11 @@ /* Begin PBXBuildFile section */ 5420395926135DC100FB00FA /* PrefsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395826135DC100FB00FA /* PrefsVC.swift */; }; 5420395F2613607600FB00FA /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395E2613607600FB00FA /* Preferences.swift */; }; - 54AB03262763858F00A29D5F /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54AB03252763858F00A29D5F /* Timer.swift */; }; - 54AB03272763858F00A29D5F /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54AB03252763858F00A29D5F /* Timer.swift */; }; 54B48B5F275F66AE006D90C5 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B48B5E275F66AE006D90C5 /* Application.swift */; }; 54B48B60275F66AE006D90C5 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B48B5E275F66AE006D90C5 /* Application.swift */; }; 54EAC806262F212B0092D14E /* GlobalKeybindPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */; }; - 54FCFD26276C883F004CE748 /* CheckboxPreferenceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54FCFD25276C883F004CE748 /* CheckboxPreferenceView.xib */; }; - 54FCFD27276C883F004CE748 /* CheckboxPreferenceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54FCFD25276C883F004CE748 /* CheckboxPreferenceView.xib */; }; + 54FCFD26276C883F004CE748 /* SelectPreferenceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54FCFD25276C883F004CE748 /* SelectPreferenceView.xib */; }; + 54FCFD27276C883F004CE748 /* SelectPreferenceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54FCFD25276C883F004CE748 /* SelectPreferenceView.xib */; }; 54FCFD2A276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54FCFD29276C8AA4004CE748 /* CheckboxPreferenceView.swift */; }; 54FCFD2B276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54FCFD29276C8AA4004CE748 /* CheckboxPreferenceView.swift */; }; 54FCFD2D276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54FCFD2C276C8D67004CE748 /* HotkeyPreferenceView.xib */; }; @@ -24,37 +22,31 @@ 54FCFD31276C8DA4004CE748 /* HotkeyPreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54FCFD2F276C8DA4004CE748 /* HotkeyPreferenceView.swift */; }; C405A4D024B9B9140062FAFA /* InternetAccessPolicy.strings in Resources */ = {isa = PBXBuildFile; fileRef = C405A4CE24B9B9130062FAFA /* InternetAccessPolicy.strings */; }; C405A4D124B9B9140062FAFA /* InternetAccessPolicy.plist in Resources */ = {isa = PBXBuildFile; fileRef = C405A4CF24B9B9140062FAFA /* InternetAccessPolicy.plist */; }; + C4068CA427B0780A00544CD5 /* CheckboxPreferenceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C4068CA327B0780A00544CD5 /* CheckboxPreferenceView.xib */; }; + C4068CA527B0780A00544CD5 /* CheckboxPreferenceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C4068CA327B0780A00544CD5 /* CheckboxPreferenceView.xib */; }; + C4068CA727B07A1300544CD5 /* SelectPreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA627B07A1300544CD5 /* SelectPreferenceView.swift */; }; + 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 */; }; C40B24F127A3106D0018C7D2 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E67279DE0540010F296 /* ServicesView.swift */; }; C40B24F227A310770018C7D2 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; }; - C40B24F327A310780018C7D2 /* 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 */; }; - C40C7F202772136000DDDCDC /* PhpEnv.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F1D2772136000DDDCDC /* PhpEnv.swift */; }; - C40C7F2227721F8200DDDCDC /* PhpInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F2E4392752F7D00020E974 /* PhpInstallation.swift */; }; - C40C7F2327721F8200DDDCDC /* ActivePhpInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4A22B019FF00E7CF16 /* ActivePhpInstallation.swift */; }; - C40C7F2427721F8200DDDCDC /* PhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4ACA38E25C754C100060C66 /* PhpExtension.swift */; }; - C40C7F2527721F9800DDDCDC /* HomebrewPackage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C412E5FB25700D5300A1FB67 /* HomebrewPackage.swift */; }; - C40C7F2627721FA200DDDCDC /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE188322D3386B00E126E5 /* Constants.swift */; }; C40C7F2827721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */; }; C40C7F2927721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */; }; - C40C7F2B2772201C00DDDCDC /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; }; C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2F27722E8D00DDDCDC /* Logger.swift */; }; C40C7F3127722E8D00DDDCDC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2F27722E8D00DDDCDC /* Logger.swift */; }; - C40C7F3227722E8D00DDDCDC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2F27722E8D00DDDCDC /* Logger.swift */; }; C412E5FC25700D5300A1FB67 /* HomebrewPackage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C412E5FB25700D5300A1FB67 /* HomebrewPackage.swift */; }; C415937F27A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; C415938027A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; C415D3B72770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; }; C415D3B82770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; }; - C415D3E12770F34D005EF286 /* AllowedArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3DE2770F34D005EF286 /* AllowedArguments.swift */; }; - C415D3E62770F540005EF286 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3E52770F540005EF286 /* main.swift */; }; C415D3E82770F692005EF286 /* AppDelegate+InterApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3E72770F692005EF286 /* AppDelegate+InterApp.swift */; }; C415D3E92770F692005EF286 /* AppDelegate+InterApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3E72770F692005EF286 /* AppDelegate+InterApp.swift */; }; C417DC74277614690015E6EE /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C417DC73277614690015E6EE /* Helpers.swift */; }; C417DC75277614690015E6EE /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C417DC73277614690015E6EE /* Helpers.swift */; }; - C417DC76277614690015E6EE /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C417DC73277614690015E6EE /* Helpers.swift */; }; C4188989275FE8CB001EF227 /* Filesystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4188988275FE8CB001EF227 /* Filesystem.swift */; }; C418898A275FE8CB001EF227 /* Filesystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4188988275FE8CB001EF227 /* Filesystem.swift */; }; C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */; }; @@ -79,6 +71,10 @@ C44C198E276E3A1C0072762D /* ProgressWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* ProgressWindow.swift */; }; C44C1991276E44CB0072762D /* ProgressWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C44C1990276E44CB0072762D /* ProgressWindow.storyboard */; }; C44C1992276E44CB0072762D /* ProgressWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C44C1990276E44CB0072762D /* ProgressWindow.storyboard */; }; + C44CCD4027AFE2FC00CE40E5 /* AlertableError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */; }; + C44CCD4127AFE2FC00CE40E5 /* AlertableError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */; }; + C44CCD4927AFF3B700CE40E5 /* MainMenu+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */; }; + C44CCD4A27AFF3BC00CE40E5 /* MainMenu+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */; }; C464ADAC275A7A3F003FCD53 /* SiteListWC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAB275A7A3F003FCD53 /* SiteListWC.swift */; }; C464ADAD275A7A3F003FCD53 /* SiteListWC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAB275A7A3F003FCD53 /* SiteListWC.swift */; }; C464ADAF275A7A69003FCD53 /* SiteListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAE275A7A69003FCD53 /* SiteListVC.swift */; }; @@ -101,8 +97,9 @@ C48D0CA325CC992000CC7490 /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0CA225CC992000CC7490 /* StatsView.swift */; }; C48D6C70279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; }; C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; }; - C48D6C72279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; }; C48D6C75279CD3E400F26D7E /* PhpVersionNumberTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */; }; + C4927F0B27B2DFC200C55AFD /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4927F0A27B2DFC200C55AFD /* Errors.swift */; }; + C4927F0C27B2DFC200C55AFD /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4927F0A27B2DFC200C55AFD /* Errors.swift */; }; C493084A279F331F009C240B /* AddSiteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4930849279F331F009C240B /* AddSiteVC.swift */; }; C493084B279F331F009C240B /* AddSiteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4930849279F331F009C240B /* AddSiteVC.swift */; }; C4998F0626175E7200B2526E /* HotKey in Frameworks */ = {isa = PBXBuildFile; productRef = C4998F0526175E7200B2526E /* HotKey */; }; @@ -121,13 +118,10 @@ C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */; }; C4B5853E2770FE3900DA4FBE /* Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853B2770FE3900DA4FBE /* Paths.swift */; }; C4B5853F2770FE3900DA4FBE /* Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853B2770FE3900DA4FBE /* Paths.swift */; }; - C4B585402770FE3900DA4FBE /* Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853B2770FE3900DA4FBE /* Paths.swift */; }; C4B585412770FE3900DA4FBE /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853C2770FE3900DA4FBE /* Shell.swift */; }; C4B585422770FE3900DA4FBE /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853C2770FE3900DA4FBE /* Shell.swift */; }; - C4B585432770FE3900DA4FBE /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853C2770FE3900DA4FBE /* Shell.swift */; }; C4B585442770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; }; C4B585452770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; }; - C4B585462770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; }; C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */; }; C4B97B76275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */; }; C4B97B78275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */; }; @@ -142,19 +136,20 @@ C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; 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 */; }; + 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 */; }; 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 */; }; C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */; }; - C4D9ADC1277610E1007277F4 /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */; }; C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */; }; C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */; }; - C4D9ADCA277611A0007277F4 /* InternalSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */; }; C4DEB7D427A5D60B00834718 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DEB7D327A5D60B00834718 /* Stats.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 */; }; - C4EC1E6E279DF87A0010F296 /* 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 */; }; @@ -170,12 +165,12 @@ C4F2E43B27530F750020E974 /* PhpInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F2E4392752F7D00020E974 /* PhpInstallation.swift */; }; C4F30B03278E16BA00755FCE /* HomebrewService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F30B02278E16BA00755FCE /* HomebrewService.swift */; }; C4F30B04278E16BA00755FCE /* HomebrewService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F30B02278E16BA00755FCE /* HomebrewService.swift */; }; - C4F30B05278E16BA00755FCE /* HomebrewService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F30B02278E16BA00755FCE /* HomebrewService.swift */; }; C4F30B07278E195800755FCE /* brew-services.json in Resources */ = {isa = PBXBuildFile; fileRef = C4F30B06278E195800755FCE /* brew-services.json */; }; C4F30B08278E195800755FCE /* brew-services.json in Resources */ = {isa = PBXBuildFile; fileRef = C4F30B06278E195800755FCE /* brew-services.json */; }; C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3ED4227834C5200AB15D8 /* CustomPrefs.swift */; }; C4F30B0A278E1A1A00755FCE /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; }; C4F30B0B278E203C00755FCE /* MainMenu+Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */; }; + C4F319C927B034A500AFF46F /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DEB7D327A5D60B00834718 /* Stats.swift */; }; C4F7809C25D80344000DBC97 /* CommandTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F7809B25D80344000DBC97 /* CommandTest.swift */; }; C4F780A825D80AE8000DBC97 /* php.ini in Resources */ = {isa = PBXBuildFile; fileRef = C4F780A725D80AE8000DBC97 /* php.ini */; }; C4F780AE25D80B37000DBC97 /* ExtensionParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F780AD25D80B37000DBC97 /* ExtensionParserTest.swift */; }; @@ -209,39 +204,27 @@ }; /* End PBXContainerItemProxy section */ -/* Begin PBXCopyFilesBuildPhase section */ - C415D3D42770F341005EF286 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ 5420395826135DC100FB00FA /* PrefsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsVC.swift; sourceTree = ""; }; 5420395E2613607600FB00FA /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; - 54AB03252763858F00A29D5F /* Timer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Timer.swift; sourceTree = ""; }; 54B48B5E275F66AE006D90C5 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; - 54FCFD25276C883F004CE748 /* CheckboxPreferenceView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CheckboxPreferenceView.xib; sourceTree = ""; }; + 54FCFD25276C883F004CE748 /* SelectPreferenceView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SelectPreferenceView.xib; sourceTree = ""; }; 54FCFD29276C8AA4004CE748 /* CheckboxPreferenceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxPreferenceView.swift; sourceTree = ""; }; 54FCFD2C276C8D67004CE748 /* HotkeyPreferenceView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HotkeyPreferenceView.xib; sourceTree = ""; }; 54FCFD2F276C8DA4004CE748 /* HotkeyPreferenceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HotkeyPreferenceView.swift; sourceTree = ""; }; C405A4CE24B9B9130062FAFA /* InternetAccessPolicy.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = InternetAccessPolicy.strings; sourceTree = ""; }; C405A4CF24B9B9140062FAFA /* InternetAccessPolicy.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = InternetAccessPolicy.plist; sourceTree = ""; }; + 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 = ""; }; 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 = ""; }; C412E5FB25700D5300A1FB67 /* HomebrewPackage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewPackage.swift; sourceTree = ""; }; C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpFrameworks.swift; sourceTree = ""; }; C415D3B62770F294005EF286 /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = ""; }; - C415D3D62770F341005EF286 /* phpmon-cli */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "phpmon-cli"; sourceTree = BUILT_PRODUCTS_DIR; }; - C415D3DE2770F34D005EF286 /* AllowedArguments.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AllowedArguments.swift; sourceTree = ""; }; - C415D3E52770F540005EF286 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; C415D3E72770F692005EF286 /* AppDelegate+InterApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+InterApp.swift"; sourceTree = ""; }; + C4168F4427ADB4A3003B6C39 /* DEVELOPER.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = DEVELOPER.md; sourceTree = ""; }; C417DC73277614690015E6EE /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; C4188988275FE8CB001EF227 /* Filesystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filesystem.swift; sourceTree = ""; }; C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PHP Monitor.app"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -263,6 +246,8 @@ C43A8A2325D9D20D00591B77 /* BrewJsonParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewJsonParserTest.swift; sourceTree = ""; }; C44C198C276E3A1C0072762D /* ProgressWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressWindow.swift; sourceTree = ""; }; C44C1990276E44CB0072762D /* ProgressWindow.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ProgressWindow.storyboard; sourceTree = ""; }; + C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertableError.swift; sourceTree = ""; }; + C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Async.swift"; sourceTree = ""; }; C464ADAB275A7A3F003FCD53 /* SiteListWC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteListWC.swift; sourceTree = ""; }; C464ADAE275A7A69003FCD53 /* SiteListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteListVC.swift; sourceTree = ""; }; C464ADB1275A87CA003FCD53 /* SiteListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteListCell.swift; sourceTree = ""; }; @@ -280,6 +265,7 @@ C48D0CA225CC992000CC7490 /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = ""; }; C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpVersionNumber.swift; sourceTree = ""; }; C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpVersionNumberTest.swift; sourceTree = ""; }; + C4927F0A27B2DFC200C55AFD /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = ""; }; C4930849279F331F009C240B /* AddSiteVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSiteVC.swift; sourceTree = ""; }; C4998F092617633900B2526E /* PrefsWC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsWC.swift; sourceTree = ""; }; C49E171E27A5736E00787921 /* PMServicesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMServicesView.swift; sourceTree = ""; }; @@ -301,6 +287,8 @@ 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 = ""; }; 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 = ""; }; @@ -333,13 +321,6 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - C415D3D32770F341005EF286 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; C41C1B3022B0097F00E7CF16 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -365,6 +346,7 @@ 5420395826135DC100FB00FA /* PrefsVC.swift */, 5420395E2613607600FB00FA /* Preferences.swift */, C4C3ED4227834C5200AB15D8 /* CustomPrefs.swift */, + C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */, C4DEB7D327A5D60B00834718 /* Stats.swift */, C41CD0272628D8E20065BBED /* Keybinds */, 54FCFD28276C88C0004CE748 /* Views */, @@ -388,8 +370,10 @@ 54FCFD28276C88C0004CE748 /* Views */ = { isa = PBXGroup; children = ( - 54FCFD25276C883F004CE748 /* CheckboxPreferenceView.xib */, + C4068CA327B0780A00544CD5 /* CheckboxPreferenceView.xib */, 54FCFD29276C8AA4004CE748 /* CheckboxPreferenceView.swift */, + 54FCFD25276C883F004CE748 /* SelectPreferenceView.xib */, + C4068CA627B07A1300544CD5 /* SelectPreferenceView.swift */, 54FCFD2C276C8D67004CE748 /* HotkeyPreferenceView.xib */, 54FCFD2F276C8DA4004CE748 /* HotkeyPreferenceView.swift */, ); @@ -431,26 +415,16 @@ path = Core; sourceTree = ""; }; - C415D3D72770F341005EF286 /* phpmon-cli */ = { - isa = PBXGroup; - children = ( - C415D3E52770F540005EF286 /* main.swift */, - C415D3DE2770F34D005EF286 /* AllowedArguments.swift */, - ); - path = "phpmon-cli"; - sourceTree = ""; - }; C41C1B2A22B0097F00E7CF16 = { isa = PBXGroup; children = ( C4F8C0A522D4FA41002EFE61 /* README.md */, C4E713562570150F00007428 /* SECURITY.md */, C4F7807425D7F7E5000DBC97 /* RELEASE.md */, + C4168F4427ADB4A3003B6C39 /* DEVELOPER.md */, C4E713572570151400007428 /* docs */, C41C1B3522B0097F00E7CF16 /* phpmon */, C4F7807A25D7F84B000DBC97 /* phpmon-tests */, - C415D3D72770F341005EF286 /* phpmon-cli */, - C4B5853A2770FE2500DA4FBE /* phpmon-common */, C41C1B3422B0097F00E7CF16 /* Products */, C4D309E72770EF2F00958BCF /* Frameworks */, ); @@ -461,7 +435,6 @@ children = ( C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */, C4F7807925D7F84B000DBC97 /* phpmon-tests.xctest */, - C415D3D62770F341005EF286 /* phpmon-cli */, ); name = Products; sourceTree = ""; @@ -469,6 +442,7 @@ C41C1B3522B0097F00E7CF16 /* phpmon */ = { isa = PBXGroup; children = ( + C4B5853A2770FE2500DA4FBE /* Common */, C41E181722CB61EB0072CF09 /* Domain */, C41C1B3F22B0098000E7CF16 /* Info.plist */, C4232EE42612526500158FC6 /* Credits.html */, @@ -492,15 +466,13 @@ isa = PBXGroup; children = ( C4AF9F6B275445D300D44ED0 /* Integrations */, - C4B13B1D25C4915000548C3A /* Core */, + C4B13B1D25C4915000548C3A /* App */, C4D9ADBD27761084007277F4 /* PHP */, C47331A0247093AC009A0597 /* Menu */, C464ADAA275A7A25003FCD53 /* SiteList */, 5420395726135DB800FB00FA /* Preferences */, C44C198F276E3A380072762D /* Progress */, C4C8E81D276F5686003AC782 /* Watcher */, - C4811D2822D70D9C00B5F6B3 /* Helpers */, - C4F8C0A222D4F100002EFE61 /* Extensions */, C4EE55B027708BB2001DF387 /* SwiftUI */, ); path = Domain; @@ -515,6 +487,15 @@ path = Progress; sourceTree = ""; }; + C44CCD4327AFE93300CE40E5 /* Errors */ = { + isa = PBXGroup; + children = ( + C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */, + C4927F0A27B2DFC200C55AFD /* Errors.swift */, + ); + path = Errors; + sourceTree = ""; + }; C464ADAA275A7A25003FCD53 /* SiteList */ = { isa = PBXGroup; children = ( @@ -532,7 +513,10 @@ isa = PBXGroup; children = ( C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */, + C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */, C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */, + C4CE3BB727B31F2E0086CA49 /* MainMenu+Switcher.swift */, + C4CE3BB927B31F670086CA49 /* MainMenu+Composer.swift */, C47331A1247093B7009A0597 /* StatusMenu.swift */, C48D0C9525CC80B100CC7490 /* HeaderView.swift */, C48D0C9925CC888B00CC7490 /* HeaderView.xib */, @@ -553,7 +537,6 @@ C474B00524C0E98C00066A22 /* LocalNotification.swift */, C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */, C4CCBA6B275C567B008C7055 /* PMWindowController.swift */, - 54AB03252763858F00A29D5F /* Timer.swift */, C4B5635D276AB09000F12CCB /* VersionExtractor.swift */, C4EC1E6C279DF87A0010F296 /* Async.swift */, ); @@ -595,7 +578,7 @@ path = Homebrew; sourceTree = ""; }; - C4B13B1D25C4915000548C3A /* Core */ = { + C4B13B1D25C4915000548C3A /* App */ = { isa = PBXGroup; children = ( C41C1B3C22B0098000E7CF16 /* Main.storyboard */, @@ -609,16 +592,19 @@ C4D8016522B1584700C6DA1B /* Startup.swift */, C4EED88827A48778006D7272 /* InterAppHandler.swift */, ); - path = Core; + path = App; sourceTree = ""; }; - C4B5853A2770FE2500DA4FBE /* phpmon-common */ = { + C4B5853A2770FE2500DA4FBE /* Common */ = { isa = PBXGroup; children = ( C40C7F2127721F7300DDDCDC /* Core */, 54B20EDF263AA22C00D3250E /* PHP */, + C44CCD4327AFE93300CE40E5 /* Errors */, + C4F8C0A222D4F100002EFE61 /* Extensions */, + C4811D2822D70D9C00B5F6B3 /* Helpers */, ); - path = "phpmon-common"; + path = Common; sourceTree = ""; }; C4C8E81D276F5686003AC782 /* Watcher */ = { @@ -715,23 +701,6 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - C415D3D52770F341005EF286 /* phpmon-cli */ = { - isa = PBXNativeTarget; - buildConfigurationList = C415D3DA2770F341005EF286 /* Build configuration list for PBXNativeTarget "phpmon-cli" */; - buildPhases = ( - C415D3D22770F341005EF286 /* Sources */, - C415D3D32770F341005EF286 /* Frameworks */, - C415D3D42770F341005EF286 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "phpmon-cli"; - productName = "phpmon-cli"; - productReference = C415D3D62770F341005EF286 /* phpmon-cli */; - productType = "com.apple.product-type.tool"; - }; C41C1B3222B0097F00E7CF16 /* PHP Monitor */ = { isa = PBXNativeTarget; buildConfigurationList = C41C1B4322B0098000E7CF16 /* Build configuration list for PBXNativeTarget "PHP Monitor" */; @@ -780,9 +749,6 @@ LastUpgradeCheck = 1320; ORGANIZATIONNAME = "Nico Verbruggen"; TargetAttributes = { - C415D3D52770F341005EF286 = { - CreatedOnToolsVersion = 13.2.1; - }; C41C1B3222B0097F00E7CF16 = { CreatedOnToolsVersion = 10.2.1; }; @@ -810,7 +776,6 @@ targets = ( C41C1B3222B0097F00E7CF16 /* PHP Monitor */, C4F7807825D7F84B000DBC97 /* phpmon-tests */, - C415D3D52770F341005EF286 /* phpmon-cli */, ); }; /* End PBXProject section */ @@ -827,9 +792,10 @@ C405A4D124B9B9140062FAFA /* InternetAccessPolicy.plist in Resources */, C44C1991276E44CB0072762D /* ProgressWindow.storyboard in Resources */, C4232EE52612526500158FC6 /* Credits.html in Resources */, - 54FCFD26276C883F004CE748 /* CheckboxPreferenceView.xib in Resources */, + 54FCFD26276C883F004CE748 /* SelectPreferenceView.xib in Resources */, C473319F2470923A009A0597 /* Localizable.strings in Resources */, C4F30B07278E195800755FCE /* brew-services.json in Resources */, + C4068CA427B0780A00544CD5 /* CheckboxPreferenceView.xib in Resources */, C4EC1E66279DE0380010F296 /* ServicesView.xib in Resources */, 54FCFD2D276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */, C405A4D024B9B9140062FAFA /* InternetAccessPolicy.strings in Resources */, @@ -841,9 +807,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 54FCFD27276C883F004CE748 /* CheckboxPreferenceView.xib in Resources */, + 54FCFD27276C883F004CE748 /* SelectPreferenceView.xib in Resources */, 54FCFD2E276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */, C4F780A825D80AE8000DBC97 /* php.ini in Resources */, + C4068CA527B0780A00544CD5 /* CheckboxPreferenceView.xib in Resources */, C43A8A2025D9D1D700591B77 /* brew.json in Resources */, C4AF9F72275445FF00D44ED0 /* valet-config.json in Resources */, C44C1992276E44CB0072762D /* ProgressWindow.storyboard in Resources */, @@ -854,33 +821,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - C415D3D22770F341005EF286 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C40C7F2427721F8200DDDCDC /* PhpExtension.swift in Sources */, - C40C7F2627721FA200DDDCDC /* Constants.swift in Sources */, - C4B585402770FE3900DA4FBE /* Paths.swift in Sources */, - C415D3E62770F540005EF286 /* main.swift in Sources */, - C40B24F327A310780018C7D2 /* Events.swift in Sources */, - C40C7F2227721F8200DDDCDC /* PhpInstallation.swift in Sources */, - C4B585432770FE3900DA4FBE /* Shell.swift in Sources */, - C4D9ADC1277610E1007277F4 /* PhpSwitcher.swift in Sources */, - C4F30B05278E16BA00755FCE /* HomebrewService.swift in Sources */, - C4EC1E6E279DF87A0010F296 /* Async.swift in Sources */, - C40C7F2327721F8200DDDCDC /* ActivePhpInstallation.swift in Sources */, - C4B585462770FE3900DA4FBE /* Command.swift in Sources */, - C4D9ADCA277611A0007277F4 /* InternalSwitcher.swift in Sources */, - C48D6C72279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */, - C40C7F2527721F9800DDDCDC /* HomebrewPackage.swift in Sources */, - C417DC76277614690015E6EE /* Helpers.swift in Sources */, - C40C7F3227722E8D00DDDCDC /* Logger.swift in Sources */, - C40C7F2B2772201C00DDDCDC /* Actions.swift in Sources */, - C415D3E12770F34D005EF286 /* AllowedArguments.swift in Sources */, - C40C7F202772136000DDDCDC /* PhpEnv.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; C41C1B2F22B0097F00E7CF16 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -894,6 +834,7 @@ C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */, 5420395926135DC100FB00FA /* PrefsVC.swift in Sources */, C43603A0275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */, + C4068CA727B07A1300544CD5 /* SelectPreferenceView.swift in Sources */, C49E171F27A5736E00787921 /* PMServicesView.swift in Sources */, C4EE55AD27708B9E001DF387 /* PMStatsView.swift in Sources */, C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, @@ -914,6 +855,7 @@ C4C3ED4327834C5200AB15D8 /* CustomPrefs.swift in Sources */, 54B48B5F275F66AE006D90C5 /* Application.swift in Sources */, C4B97B78275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */, + C4CE3BB827B31F2E0086CA49 /* MainMenu+Switcher.swift in Sources */, C415937F27A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */, C4811D2422D70A4700B5F6B3 /* App.swift in Sources */, C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */, @@ -926,7 +868,7 @@ C41CA5ED2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */, C412E5FC25700D5300A1FB67 /* HomebrewPackage.swift in Sources */, C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */, - 54AB03262763858F00A29D5F /* Timer.swift in Sources */, + C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */, C4C8E81B276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */, C417DC74277614690015E6EE /* Helpers.swift in Sources */, C415D3E82770F692005EF286 /* AppDelegate+InterApp.swift in Sources */, @@ -934,9 +876,12 @@ C42759672627662800093CAE /* NSMenuExtension.swift in Sources */, C464ADAF275A7A69003FCD53 /* SiteListVC.swift in Sources */, C4EC1E6D279DF87A0010F296 /* Async.swift in Sources */, + C44CCD4927AFF3B700CE40E5 /* MainMenu+Async.swift in Sources */, C4EC1E73279DFCF40010F296 /* Events.swift in Sources */, + C4927F0B27B2DFC200C55AFD /* Errors.swift in Sources */, C4B5853E2770FE3900DA4FBE /* Paths.swift in Sources */, C41C1B4B22B019FF00E7CF16 /* ActivePhpInstallation.swift in Sources */, + C44CCD4027AFE2FC00CE40E5 /* AlertableError.swift in Sources */, C4188989275FE8CB001EF227 /* Filesystem.swift in Sources */, C4B97B7B275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */, C4EED88927A48778006D7272 /* InterAppHandler.swift in Sources */, @@ -944,6 +889,7 @@ C476FF9822B0DD830098105B /* Alert.swift in Sources */, C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */, C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */, + C4CE3BBA27B31F670086CA49 /* MainMenu+Composer.swift in Sources */, C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */, C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */, C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */, @@ -967,7 +913,6 @@ C4EE55AE27708B9E001DF387 /* PMStatsView.swift in Sources */, C41CA5EE2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */, C4F780C425D80B75000DBC97 /* MainMenu.swift in Sources */, - 54AB03272763858F00A29D5F /* Timer.swift in Sources */, 54FCFD2B276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */, C415D3B82770F294005EF286 /* Actions.swift in Sources */, 54B48B60275F66AE006D90C5 /* Application.swift in Sources */, @@ -976,12 +921,14 @@ C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */, C4F780CC25D80B75000DBC97 /* ActivePhpInstallation.swift in Sources */, C4F780B125D80B4D000DBC97 /* PhpExtension.swift in Sources */, + C4068CA827B07A1300544CD5 /* SelectPreferenceView.swift in Sources */, C4F780CE25D80B75000DBC97 /* LocalNotification.swift in Sources */, C40C7F2927721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */, C4FBFC532616485F00CDB8E1 /* PhpVersionDetectionTest.swift in Sources */, C43A8A2425D9D20D00591B77 /* BrewJsonParserTest.swift in Sources */, C4F780CA25D80B75000DBC97 /* HomebrewPackage.swift in Sources */, C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */, + C4F319C927B034A500AFF46F /* Stats.swift in Sources */, C4F30B04278E16BA00755FCE /* HomebrewService.swift in Sources */, C4AF9F7B2754499000D44ED0 /* Valet.swift in Sources */, C4F780C025D80B6E000DBC97 /* Startup.swift in Sources */, @@ -1000,15 +947,19 @@ C481F79726164A78004FBCFF /* PrefsVC.swift in Sources */, C41E871B2763D42300161EE0 /* SiteListVC+ContextMenu.swift in Sources */, C40C7F3127722E8D00DDDCDC /* Logger.swift in Sources */, + C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */, C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */, C464ADB3275A87CA003FCD53 /* SiteListCell.swift in Sources */, C415D3E92770F692005EF286 /* AppDelegate+InterApp.swift in Sources */, C4AF9F78275447F100D44ED0 /* ValetConfigParserTest.swift in Sources */, + C4CE3BBC27B324250086CA49 /* MainMenu+Composer.swift in Sources */, C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */, C417DC75277614690015E6EE /* Helpers.swift in Sources */, C4B97B7C275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */, C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */, + C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */, C4F7809C25D80344000DBC97 /* CommandTest.swift in Sources */, + C44CCD4127AFE2FC00CE40E5 /* AlertableError.swift in Sources */, C4F780BA25D80B62000DBC97 /* AppDelegate.swift in Sources */, 54FCFD31276C8DA4004CE748 /* HotkeyPreferenceView.swift in Sources */, C4998F0B2617633900B2526E /* PrefsWC.swift in Sources */, @@ -1027,6 +978,8 @@ C40B24F127A3106D0018C7D2 /* ServicesView.swift in Sources */, C4F780C525D80B75000DBC97 /* MenuBarImageGenerator.swift in Sources */, C4F780B725D80B5D000DBC97 /* App.swift in Sources */, + C4927F0C27B2DFC200C55AFD /* Errors.swift in Sources */, + C44CCD4A27AFF3BC00CE40E5 /* MainMenu+Async.swift in Sources */, C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */, C4F780C925D80B75000DBC97 /* StringExtension.swift in Sources */, C4B5853F2770FE3900DA4FBE /* Paths.swift in Sources */, @@ -1065,34 +1018,6 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - C415D3DB2770F341005EF286 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 8M54J5J787; - ENABLE_HARDENED_RUNTIME = YES; - MACOSX_DEPLOYMENT_TARGET = 11.0; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - C415D3DC2770F341005EF286 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 8M54J5J787; - ENABLE_HARDENED_RUNTIME = YES; - MACOSX_DEPLOYMENT_TARGET = 11.0; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; C41C1B4122B0098000E7CF16 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1218,7 +1143,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 560; + CURRENT_PROJECT_VERSION = 610; DEVELOPMENT_TEAM = 8M54J5J787; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = phpmon/Info.plist; @@ -1227,7 +1152,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 5.0; + MARKETING_VERSION = 5.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1243,7 +1168,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 560; + CURRENT_PROJECT_VERSION = 610; DEVELOPMENT_TEAM = 8M54J5J787; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = phpmon/Info.plist; @@ -1252,7 +1177,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 5.0; + MARKETING_VERSION = 5.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1305,15 +1230,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - C415D3DA2770F341005EF286 /* Build configuration list for PBXNativeTarget "phpmon-cli" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C415D3DB2770F341005EF286 /* Debug */, - C415D3DC2770F341005EF286 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; C41C1B2E22B0097F00E7CF16 /* Build configuration list for PBXProject "PHP Monitor" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor CLI.xcscheme b/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor CLI.xcscheme deleted file mode 100644 index 41be842..0000000 --- a/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor CLI.xcscheme +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/README.md b/README.md index 19a9653..6a8e202 100644 --- a/README.md +++ b/README.md @@ -320,9 +320,9 @@ You can always still ask Valet using the command line, should it be necessary. I
After running PHP Monitor, Homebrew sometimes has issues with `brew upgrade` or `brew cleanup`! -This is a security feature of Homebrew. When you start a service as an administrator, the root user becomes the owner of relevant binaries. You will need to manually clean up those folders yourself using `rm -rf` (or by manually removing those folders via Finder). +You can now use **First Aid & Services > Restore Homebrew Permissions** to (temporarily) resolve this issue and allow for a clean and painless `brew upgrade` or `brew cleanup` process. -If you would like to know more, consult [this issue](https://github.com/nicoverbruggen/phpmon/issues/85) for more information. +If you would like to know more, consult [this issue](https://github.com/nicoverbruggen/phpmon/issues/85) for more information about why this is needed.
@@ -399,15 +399,4 @@ I have done my best to annotate as much as humanly possible, and have avoided us I also have a few tests for key parts of the application that I found needed to be tested. In the future, I would like to add even more tests for some of the UI stuff, but for now the tests are more unit tests than feature tests. -## 🔧 Build instructions - -build button in Xcode - -If you'd like to build PHP Monitor yourself, you need: - -* Xcode (usually the latest version) -* The contents of this repository - -Once you have downloaded this repository, open `PHP Monitor.xcodeproj`, and you should be able to immediately build the app for your system by pressing Cmd-R. This will create a debug build. (If Xcode complains about code signing, you can turn it off.) - -If you'd like to create a production build, choose "Any Mac" as the target and select Product > Archive. +For more detailed information for developers, please see [the documentation file for developers](./DEVS.md). diff --git a/assets/icons.afdesign b/assets/icons.afdesign new file mode 100644 index 0000000..a78eaf1 Binary files /dev/null and b/assets/icons.afdesign differ diff --git a/phpmon-cli/AllowedArguments.swift b/phpmon-cli/AllowedArguments.swift deleted file mode 100644 index e12a279..0000000 --- a/phpmon-cli/AllowedArguments.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// AllowedArguments.swift -// phpmon-cli -// -// Created by Nico Verbruggen on 20/12/2021. -// Copyright © 2021 Nico Verbruggen. All rights reserved. -// - -import Foundation - -enum AllowedArguments: String, CaseIterable { - case use = "use" - case performSwitch = "switch" - case fix = "fix" - case help = "help" - - static func has(_ string: String) -> Bool { - return Self.allCases.contains { arg in - return arg.rawValue == string - } - } - - static var rawValues: [String] { - return Self.allCases.map { $0.rawValue } - } -} diff --git a/phpmon-cli/main.swift b/phpmon-cli/main.swift deleted file mode 100644 index 8b986a2..0000000 --- a/phpmon-cli/main.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// main.swift -// phpmon-cli -// -// Created by Nico Verbruggen on 20/12/2021. -// Copyright © 2021 Nico Verbruggen. All rights reserved. -// - -import Foundation - -let toolver = "0.1 (early access)" - -let log = Log.shared -log.verbosity = .info - -if CommandLine.arguments.contains("-q") || CommandLine.arguments.contains("--quiet") { - Log.shared.verbosity = .warning -} -if CommandLine.arguments.contains("-p") || CommandLine.arguments.contains("--performance") { - Log.shared.verbosity = .performance -} - -var argument = "help" -if CommandLine.arguments.count > 1 { - argument = CommandLine.arguments[1] -} - -if !AllowedArguments.has(argument) { - Log.err("The supported arguments are: \(AllowedArguments.rawValues)") - exit(1) -} - -let action = AllowedArguments.init(rawValue: argument) - -switch action { -case .use, .performSwitch: - if !Shell.fileExists("\(Paths.binPath)/php") { - Log.err("PHP is currently not linked. Attempting quick fix...") - _ = Shell.user.executeSynchronously("brew link php", requiresPath: true) - } - - let phpenv = PhpEnv.shared - PhpEnv.detectPhpVersions() - - if CommandLine.arguments.count < 3 { - Log.err("You must enter at least two additional arguments when using this command.") - exit(1) - } - - let version = CommandLine.arguments[2].replacingOccurrences(of: "php@", with: "") - if phpenv.availablePhpVersions.contains(version) { - Log.info("Switching to PHP \(version)...") - Actions.switchToPhpVersion( - version: version, - availableVersions: phpenv.availablePhpVersions, - completed: { - Log.info("The switch has been completed.") - exit(0) - } - ) - } else { - Log.err("A PHP installation with version \(version) is not installed.") - Log.err("The installed versions are: \(phpenv.availablePhpVersions.joined(separator: ", ")).") - Log.err("If this version is available, you may be able to install it by using `brew install php@\(version)`.") - exit(1) - } -case .fix: - Log.info("Fixing your PHP installation...") - Actions.fixMyPhp() - Log.info("All operations completed. You can check which version of PHP is linked by using `php -v`.") - exit(0) -case .help: - print(""" - =============================================================== - PHP MONITOR CLI \(toolver) - by Nico Verbruggen - =============================================================== - - Gives access to the quick version switcher from PHP Monitor, - but without the GUI and 100% of the speed! - - SUPPORTED COMMANDS - - * use {version}: Switch to a specific version of PHP. - (e.g. `phpmon-cli use 8.0`) - * switch {version}: Alias for the `use` command. - * fix Attempts to unlink all PHP versions, - and link the latest version of PHP. - * help: Show this help. - - SUPPORTED FLAGS - - * `-q / --quiet`: Silences all logs except for warnings and exceptions. - * `-p / --perf`: Enables performance mode. - - """) - exit(0) -case .none: - Log.err("Action not recognized!") - exit(1) -} - -RunLoop.main.run() diff --git a/phpmon-tests/PhpVersionNumberTest.swift b/phpmon-tests/PhpVersionNumberTest.swift index 2a059e3..8ef2ac4 100644 --- a/phpmon-tests/PhpVersionNumberTest.swift +++ b/phpmon-tests/PhpVersionNumberTest.swift @@ -11,6 +11,10 @@ import XCTest class PhpVersionNumberTest: XCTestCase { func testCanDeconstructPhpVersion() throws { + XCTAssertEqual( + try! PhpVersionNumber.parse("PHP 8.1.0RC5-dev"), + PhpVersionNumber(major: 8, minor: 1, patch: 0) + ) XCTAssertEqual( PhpVersionNumber.make(from: "8.0.11"), PhpVersionNumber(major: 8, minor: 0, patch: 11) @@ -29,6 +33,12 @@ class PhpVersionNumberTest: XCTestCase { ) } + func testPhpVersionNumberParse() throws { + XCTAssertThrowsError(try PhpVersionNumber.parse("OOF")) { error in + XCTAssertTrue(error is VersionParseError) + } + } + func testCanCheckFixedConstraints() throws { XCTAssertEqual( PhpVersionNumberCollection diff --git a/phpmon/Assets.xcassets/IconLinked.imageset/Contents.json b/phpmon/Assets.xcassets/IconLinked.imageset/Contents.json index 6cb3d9a..89391b7 100644 --- a/phpmon/Assets.xcassets/IconLinked.imageset/Contents.json +++ b/phpmon/Assets.xcassets/IconLinked.imageset/Contents.json @@ -1,11 +1,12 @@ { "images" : [ { + "filename" : "Linked.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "link.svg", + "filename" : "Linked@2x.png", "idiom" : "universal", "scale" : "2x" }, diff --git a/phpmon/Assets.xcassets/IconLinked.imageset/Linked.png b/phpmon/Assets.xcassets/IconLinked.imageset/Linked.png new file mode 100644 index 0000000..a0e0f4d Binary files /dev/null and b/phpmon/Assets.xcassets/IconLinked.imageset/Linked.png differ diff --git a/phpmon/Assets.xcassets/IconLinked.imageset/Linked@2x.png b/phpmon/Assets.xcassets/IconLinked.imageset/Linked@2x.png new file mode 100644 index 0000000..cf1ff87 Binary files /dev/null and b/phpmon/Assets.xcassets/IconLinked.imageset/Linked@2x.png differ diff --git a/phpmon/Assets.xcassets/IconLinked.imageset/link.svg b/phpmon/Assets.xcassets/IconLinked.imageset/link.svg deleted file mode 100644 index f0fdbf4..0000000 --- a/phpmon/Assets.xcassets/IconLinked.imageset/link.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/phpmon/Assets.xcassets/IconParked.imageset/Contents.json b/phpmon/Assets.xcassets/IconParked.imageset/Contents.json index 24b6de7..f07a245 100644 --- a/phpmon/Assets.xcassets/IconParked.imageset/Contents.json +++ b/phpmon/Assets.xcassets/IconParked.imageset/Contents.json @@ -1,11 +1,12 @@ { "images" : [ { + "filename" : "Parked.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "car-alt.svg", + "filename" : "Parked@2x.png", "idiom" : "universal", "scale" : "2x" }, diff --git a/phpmon/Assets.xcassets/IconParked.imageset/Parked.png b/phpmon/Assets.xcassets/IconParked.imageset/Parked.png new file mode 100644 index 0000000..810a32e Binary files /dev/null and b/phpmon/Assets.xcassets/IconParked.imageset/Parked.png differ diff --git a/phpmon/Assets.xcassets/IconParked.imageset/Parked@2x.png b/phpmon/Assets.xcassets/IconParked.imageset/Parked@2x.png new file mode 100644 index 0000000..98b6b4c Binary files /dev/null and b/phpmon/Assets.xcassets/IconParked.imageset/Parked@2x.png differ diff --git a/phpmon/Assets.xcassets/IconParked.imageset/car-alt.svg b/phpmon/Assets.xcassets/IconParked.imageset/car-alt.svg deleted file mode 100644 index 90a786e..0000000 --- a/phpmon/Assets.xcassets/IconParked.imageset/car-alt.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/phpmon/Assets.xcassets/Menu Bar Icons/Contents.json b/phpmon/Assets.xcassets/Menu Bar Icons/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/phpmon/Assets.xcassets/Menu Bar Icons/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Contents.json b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Contents.json new file mode 100644 index 0000000..5c666d4 --- /dev/null +++ b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "Menu Bar Elephant.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Menu Bar Elephant@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Menu Bar Elephant.png b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Menu Bar Elephant.png new file mode 100644 index 0000000..8dd923e Binary files /dev/null and b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Menu Bar Elephant.png differ diff --git a/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Menu Bar Elephant@2x.png b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Menu Bar Elephant@2x.png new file mode 100644 index 0000000..86bc7e8 Binary files /dev/null and b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Menu Bar Elephant@2x.png differ diff --git a/phpmon/Assets.xcassets/StatusBarPHP.imageset/Contents.json b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Contents.json similarity index 78% rename from phpmon/Assets.xcassets/StatusBarPHP.imageset/Contents.json rename to phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Contents.json index effdb9c..0f8299a 100644 --- a/phpmon/Assets.xcassets/StatusBarPHP.imageset/Contents.json +++ b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Contents.json @@ -1,11 +1,12 @@ { "images" : [ { + "filename" : "Menu Bar.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "php@2x.png", + "filename" : "Menu Bar@2x.png", "idiom" : "universal", "scale" : "2x" }, diff --git a/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Menu Bar.png b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Menu Bar.png new file mode 100644 index 0000000..179b98e Binary files /dev/null and b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Menu Bar.png differ diff --git a/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Menu Bar@2x.png b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Menu Bar@2x.png new file mode 100644 index 0000000..522077c Binary files /dev/null and b/phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Menu Bar@2x.png differ diff --git a/phpmon/Assets.xcassets/ServiceLoading.imageset/Contents.json b/phpmon/Assets.xcassets/ServiceLoading.imageset/Contents.json index b7c29f9..b5851cb 100644 --- a/phpmon/Assets.xcassets/ServiceLoading.imageset/Contents.json +++ b/phpmon/Assets.xcassets/ServiceLoading.imageset/Contents.json @@ -1,11 +1,12 @@ { "images" : [ { + "filename" : "ServiceLoading.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "question-circle.svg", + "filename" : "ServiceLoading@2x.png", "idiom" : "universal", "scale" : "2x" }, diff --git a/phpmon/Assets.xcassets/ServiceLoading.imageset/ServiceLoading.png b/phpmon/Assets.xcassets/ServiceLoading.imageset/ServiceLoading.png new file mode 100644 index 0000000..2967845 Binary files /dev/null and b/phpmon/Assets.xcassets/ServiceLoading.imageset/ServiceLoading.png differ diff --git a/phpmon/Assets.xcassets/ServiceLoading.imageset/ServiceLoading@2x.png b/phpmon/Assets.xcassets/ServiceLoading.imageset/ServiceLoading@2x.png new file mode 100644 index 0000000..79ba93a Binary files /dev/null and b/phpmon/Assets.xcassets/ServiceLoading.imageset/ServiceLoading@2x.png differ diff --git a/phpmon/Assets.xcassets/ServiceLoading.imageset/question-circle.svg b/phpmon/Assets.xcassets/ServiceLoading.imageset/question-circle.svg deleted file mode 100644 index df1f089..0000000 --- a/phpmon/Assets.xcassets/ServiceLoading.imageset/question-circle.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/phpmon/Assets.xcassets/ServiceOff.imageset/Contents.json b/phpmon/Assets.xcassets/ServiceOff.imageset/Contents.json index 5aba3d7..10f5302 100644 --- a/phpmon/Assets.xcassets/ServiceOff.imageset/Contents.json +++ b/phpmon/Assets.xcassets/ServiceOff.imageset/Contents.json @@ -1,11 +1,12 @@ { "images" : [ { + "filename" : "ServiceOff.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "times-circle.svg", + "filename" : "ServiceOff@2x.png", "idiom" : "universal", "scale" : "2x" }, diff --git a/phpmon/Assets.xcassets/ServiceOff.imageset/ServiceOff.png b/phpmon/Assets.xcassets/ServiceOff.imageset/ServiceOff.png new file mode 100644 index 0000000..326901b Binary files /dev/null and b/phpmon/Assets.xcassets/ServiceOff.imageset/ServiceOff.png differ diff --git a/phpmon/Assets.xcassets/ServiceOff.imageset/ServiceOff@2x.png b/phpmon/Assets.xcassets/ServiceOff.imageset/ServiceOff@2x.png new file mode 100644 index 0000000..9344277 Binary files /dev/null and b/phpmon/Assets.xcassets/ServiceOff.imageset/ServiceOff@2x.png differ diff --git a/phpmon/Assets.xcassets/ServiceOff.imageset/times-circle.svg b/phpmon/Assets.xcassets/ServiceOff.imageset/times-circle.svg deleted file mode 100644 index b5d5eba..0000000 --- a/phpmon/Assets.xcassets/ServiceOff.imageset/times-circle.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/phpmon/Assets.xcassets/ServiceOn.imageset/Contents.json b/phpmon/Assets.xcassets/ServiceOn.imageset/Contents.json index e3569a7..b1566c6 100644 --- a/phpmon/Assets.xcassets/ServiceOn.imageset/Contents.json +++ b/phpmon/Assets.xcassets/ServiceOn.imageset/Contents.json @@ -1,11 +1,12 @@ { "images" : [ { + "filename" : "ServiceOn.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "check-circle.svg", + "filename" : "ServiceOn@2x.png", "idiom" : "universal", "scale" : "2x" }, diff --git a/phpmon/Assets.xcassets/ServiceOn.imageset/ServiceOn.png b/phpmon/Assets.xcassets/ServiceOn.imageset/ServiceOn.png new file mode 100644 index 0000000..5f424a3 Binary files /dev/null and b/phpmon/Assets.xcassets/ServiceOn.imageset/ServiceOn.png differ diff --git a/phpmon/Assets.xcassets/ServiceOn.imageset/ServiceOn@2x.png b/phpmon/Assets.xcassets/ServiceOn.imageset/ServiceOn@2x.png new file mode 100644 index 0000000..c40fe32 Binary files /dev/null and b/phpmon/Assets.xcassets/ServiceOn.imageset/ServiceOn@2x.png differ diff --git a/phpmon/Assets.xcassets/ServiceOn.imageset/check-circle.svg b/phpmon/Assets.xcassets/ServiceOn.imageset/check-circle.svg deleted file mode 100644 index 5673a79..0000000 --- a/phpmon/Assets.xcassets/ServiceOn.imageset/check-circle.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/phpmon/Assets.xcassets/StatusBarPHP.imageset/php@2x.png b/phpmon/Assets.xcassets/StatusBarPHP.imageset/php@2x.png deleted file mode 100644 index 497b4a8..0000000 Binary files a/phpmon/Assets.xcassets/StatusBarPHP.imageset/php@2x.png and /dev/null differ diff --git a/phpmon-common/Core/Actions.swift b/phpmon/Common/Core/Actions.swift similarity index 72% rename from phpmon-common/Core/Actions.swift rename to phpmon/Common/Core/Actions.swift index fc41ec7..23a677b 100644 --- a/phpmon-common/Core/Actions.swift +++ b/phpmon/Common/Core/Actions.swift @@ -34,17 +34,39 @@ class Actions { brew("services stop dnsmasq", sudo: true) } - /** - Kindly asks Valet to switch to a specific PHP version. - */ - public static func switchToPhpVersionUsingValet( - version: String, - availableVersions: [String], - completed: @escaping () -> Void - ) { - Log.info("Switching to \(version) using Valet") - Log.info(valet("use php@\(version)")) - completed() + public static func fixHomebrewPermissions() throws + { + var servicesCommands = [ + "\(Paths.brew) services stop nginx", + "\(Paths.brew) services stop dnsmasq", + ] + var cellarCommands = [ + "chown -R \(Paths.whoami):staff \(Paths.cellarPath)/nginx", + "chown -R \(Paths.whoami):staff \(Paths.cellarPath)/dnsmasq" + ] + + PhpEnv.shared.availablePhpVersions.forEach { version in + let formula = version == PhpEnv.brewPhpVersion + ? "php" + : "php@\(version)" + servicesCommands.append("\(Paths.brew) services stop \(formula)") + cellarCommands.append("chown -R \(Paths.whoami):staff \(Paths.cellarPath)/\(formula)") + } + + let script = + servicesCommands.joined(separator: " && ") + + " && " + + cellarCommands.joined(separator: " && ") + + let appleScript = NSAppleScript( + source: "do shell script \"\(script)\" with administrator privileges" + ) + + let eventResult: NSAppleEventDescriptor? = appleScript?.executeAndReturnError(nil) + + if (eventResult == nil) { + throw HomebrewPermissionError(kind: .applescriptNilError) + } } // MARK: - Finding Config Files diff --git a/phpmon-common/Core/Command.swift b/phpmon/Common/Core/Command.swift similarity index 100% rename from phpmon-common/Core/Command.swift rename to phpmon/Common/Core/Command.swift diff --git a/phpmon-common/Core/Constants.swift b/phpmon/Common/Core/Constants.swift similarity index 100% rename from phpmon-common/Core/Constants.swift rename to phpmon/Common/Core/Constants.swift diff --git a/phpmon-common/Core/Events.swift b/phpmon/Common/Core/Events.swift similarity index 100% rename from phpmon-common/Core/Events.swift rename to phpmon/Common/Core/Events.swift diff --git a/phpmon-common/Core/Helpers.swift b/phpmon/Common/Core/Helpers.swift similarity index 100% rename from phpmon-common/Core/Helpers.swift rename to phpmon/Common/Core/Helpers.swift diff --git a/phpmon-common/Core/Logger.swift b/phpmon/Common/Core/Logger.swift similarity index 93% rename from phpmon-common/Core/Logger.swift rename to phpmon/Common/Core/Logger.swift index 87f2e81..8616528 100644 --- a/phpmon-common/Core/Logger.swift +++ b/phpmon/Common/Core/Logger.swift @@ -27,13 +27,13 @@ class Log { static func err(_ item: Any) { if Verbosity.error.isApplicable() { - print(item) + print("[ERR] \(item)") } } static func warn(_ item: Any) { if Verbosity.warning.isApplicable() { - print(item) + print("[WRN] \(item)") } } diff --git a/phpmon-common/Core/Paths.swift b/phpmon/Common/Core/Paths.swift similarity index 87% rename from phpmon-common/Core/Paths.swift rename to phpmon/Common/Core/Paths.swift index 9083041..a227cc3 100644 --- a/phpmon-common/Core/Paths.swift +++ b/phpmon/Common/Core/Paths.swift @@ -20,7 +20,7 @@ public class Paths { private var userName : String init() { - baseDir = Shell.fileExists("\(HomebrewDir.opt.rawValue)/bin/brew") ? .opt : .usr + baseDir = FileManager.default.fileExists(atPath: "\(HomebrewDir.opt.rawValue)/bin/brew") ? .opt : .usr userName = String(Shell.pipe("whoami").split(separator: "\n")[0]) } @@ -48,6 +48,10 @@ public class Paths { return shared.userName } + public static var cellarPath: String { + return "\(shared.baseDir.rawValue)/Cellar" + } + public static var binPath: String { return "\(shared.baseDir.rawValue)/bin" } diff --git a/phpmon-common/Core/Shell.swift b/phpmon/Common/Core/Shell.swift similarity index 95% rename from phpmon-common/Core/Shell.swift rename to phpmon/Common/Core/Shell.swift index a1ae6c1..8ea3e2e 100644 --- a/phpmon-common/Core/Shell.swift +++ b/phpmon/Common/Core/Shell.swift @@ -105,12 +105,12 @@ public class Shell { } /** - Checks if a file exists at the provided path. - Uses `/bin/echo` instead of the `builtin` (which does not support `-n`). + 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 escapedPath = path.replacingOccurrences(of: " ", with: "\\ ") - return Shell.pipe("if [ -f \(escapedPath) ]; then /bin/echo -n \"0\"; fi") == "0" + let fullPath = path.replacingOccurrences(of: "~", with: "/Users/\(Paths.whoami)") + return FileManager.default.fileExists(atPath: fullPath) } /** diff --git a/phpmon/Common/Errors/AlertableError.swift b/phpmon/Common/Errors/AlertableError.swift new file mode 100644 index 0000000..f32540b --- /dev/null +++ b/phpmon/Common/Errors/AlertableError.swift @@ -0,0 +1,13 @@ +// +// Errors.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 06/02/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Foundation + +protocol AlertableError { + func getErrorMessageKey() -> String +} diff --git a/phpmon/Common/Errors/Errors.swift b/phpmon/Common/Errors/Errors.swift new file mode 100644 index 0000000..1678814 --- /dev/null +++ b/phpmon/Common/Errors/Errors.swift @@ -0,0 +1,29 @@ +// +// VersionParseError.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 08/02/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Foundation + +// MARK: - Alertable Errors +// These errors must be resolved by the user. + +struct HomebrewPermissionError: Error, AlertableError { + enum Kind: String { + case applescriptNilError = "homebrew_permissions.applescript_returned_nil" + } + + let kind: Kind + + func getErrorMessageKey() -> String { + return "alert.errors.\(self.kind.rawValue)" + } +} + +// MARK: - Errors that do not have an associated alert message +// The errors must be resolved by the developer. + +struct VersionParseError: Error {} diff --git a/phpmon/Domain/Extensions/DateExtension.swift b/phpmon/Common/Extensions/DateExtension.swift similarity index 100% rename from phpmon/Domain/Extensions/DateExtension.swift rename to phpmon/Common/Extensions/DateExtension.swift diff --git a/phpmon/Domain/Extensions/NSMenuExtension.swift b/phpmon/Common/Extensions/NSMenuExtension.swift similarity index 100% rename from phpmon/Domain/Extensions/NSMenuExtension.swift rename to phpmon/Common/Extensions/NSMenuExtension.swift diff --git a/phpmon/Domain/Extensions/StringExtension.swift b/phpmon/Common/Extensions/StringExtension.swift similarity index 100% rename from phpmon/Domain/Extensions/StringExtension.swift rename to phpmon/Common/Extensions/StringExtension.swift diff --git a/phpmon/Domain/Extensions/XibLoadable.swift b/phpmon/Common/Extensions/XibLoadable.swift similarity index 100% rename from phpmon/Domain/Extensions/XibLoadable.swift rename to phpmon/Common/Extensions/XibLoadable.swift diff --git a/phpmon/Domain/Helpers/Alert.swift b/phpmon/Common/Helpers/Alert.swift similarity index 76% rename from phpmon/Domain/Helpers/Alert.swift rename to phpmon/Common/Helpers/Alert.swift index 897e310..25327a7 100644 --- a/phpmon/Domain/Helpers/Alert.swift +++ b/phpmon/Common/Helpers/Alert.swift @@ -51,6 +51,9 @@ 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, @@ -59,5 +62,20 @@ class Alert { 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/Domain/Helpers/Application.swift b/phpmon/Common/Helpers/Application.swift similarity index 100% rename from phpmon/Domain/Helpers/Application.swift rename to phpmon/Common/Helpers/Application.swift diff --git a/phpmon/Domain/Helpers/Async.swift b/phpmon/Common/Helpers/Async.swift similarity index 100% rename from phpmon/Domain/Helpers/Async.swift rename to phpmon/Common/Helpers/Async.swift diff --git a/phpmon/Domain/Helpers/Filesystem.swift b/phpmon/Common/Helpers/Filesystem.swift similarity index 100% rename from phpmon/Domain/Helpers/Filesystem.swift rename to phpmon/Common/Helpers/Filesystem.swift diff --git a/phpmon/Domain/Helpers/LocalNotification.swift b/phpmon/Common/Helpers/LocalNotification.swift similarity index 100% rename from phpmon/Domain/Helpers/LocalNotification.swift rename to phpmon/Common/Helpers/LocalNotification.swift diff --git a/phpmon/Domain/Helpers/MenuBarImageGenerator.swift b/phpmon/Common/Helpers/MenuBarImageGenerator.swift similarity index 58% rename from phpmon/Domain/Helpers/MenuBarImageGenerator.swift rename to phpmon/Common/Helpers/MenuBarImageGenerator.swift index 21621a7..a68d15a 100644 --- a/phpmon/Domain/Helpers/MenuBarImageGenerator.swift +++ b/phpmon/Common/Helpers/MenuBarImageGenerator.swift @@ -42,7 +42,7 @@ class MenuBarImageGenerator { let targetImage: NSImage = NSImage(size: image.size) - let rep: NSBitmapImageRep = NSBitmapImageRep( + let representation: NSBitmapImageRep = NSBitmapImageRep( bitmapDataPlanes: nil, pixelsWide: Int(image.size.width), pixelsHigh: Int(image.size.height), @@ -55,7 +55,7 @@ class MenuBarImageGenerator { bitsPerPixel: 0 )! - targetImage.addRepresentation(rep) + targetImage.addRepresentation(representation) targetImage.lockFocus() image.draw(in: imageRect) @@ -69,32 +69,69 @@ class MenuBarImageGenerator { The same as before, but also attempts to add an icon to the left. */ public static func textToImageWithIcon(text: String) -> NSImage { - let textImage = self.textToImage(text: text) - let iconImage = NSImage(named: "StatusBarPHP")! - let iconWidthSize = iconImage.size.width - let divider = iconWidthSize + // We'll start out with the image containing the text + let textImage = self.textToImage(text: text) + + // Then we'll fetch the image we want on the left + var iconType = Preferences.preferences[.iconTypeToDisplay] as? String + if iconType == nil { + Log.warn("Invalid icon type found, using the default") + iconType = MenuBarIcon.iconPhp.rawValue + } + + let iconImage = NSImage(named: "MenuBar_\(iconType!)")! + + // We'll need to reference the width of the icon a bunch of times + let iconWidthSize = iconImage.size.width + + // There will also be an additional divider between the image and the text (image) + let divider: CGFloat = 3 + + // Use a fixed size for the height of the menu bar (18pt) let imageRect = CGRect( x: 0, y: 0, - width: textImage.size.width + divider, - height: textImage.size.height + width: textImage.size.width + iconWidthSize + divider, + height: 18 ) + // Create a new image, we'll draw the text and our icon in there let image: NSImage = NSImage(size: imageRect.size) image.lockFocus() + + // Calculate the offset between the image and the text + let offset = imageRect.size.width - textImage.size.width - let difference = imageRect.size.width - textImage.size.width + // Draw the text with a negative x offset (so there is room on the left for the icon) + textImage.draw( + in: imageRect, + from: NSRect( + x: -offset, + y: 0, + width: textImage.size.width + offset, + height: textImage.size.height + ), + operation: .overlay, + fraction: 1 + ) - textImage.draw(in: imageRect, from: NSRect( - x: -difference, - y: 0, width: textImage.size.width + difference, - height: textImage.size.height - ), operation: .overlay, fraction: 1) - - iconImage.draw(in: imageRect, from: NSRect(x: 0, y: 0, width: imageRect.size.width * 1.6, height: imageRect.size.height * 2.0), operation: .overlay, fraction: 1) + // Draw the icon directly in the left of the imageRect (where we left space) + iconImage.draw( + in: imageRect, + from: NSRect( + x: 0, + y: 0, + width: imageRect.size.width, + height: imageRect.size.height + ), + operation: .overlay, + fraction: 1 + ) + // We're done with this image image.unlockFocus() + return image } diff --git a/phpmon/Domain/Helpers/PMWindowController.swift b/phpmon/Common/Helpers/PMWindowController.swift similarity index 100% rename from phpmon/Domain/Helpers/PMWindowController.swift rename to phpmon/Common/Helpers/PMWindowController.swift diff --git a/phpmon/Domain/Helpers/VersionExtractor.swift b/phpmon/Common/Helpers/VersionExtractor.swift similarity index 92% rename from phpmon/Domain/Helpers/VersionExtractor.swift rename to phpmon/Common/Helpers/VersionExtractor.swift index 69abe9b..7ac49de 100644 --- a/phpmon/Domain/Helpers/VersionExtractor.swift +++ b/phpmon/Common/Helpers/VersionExtractor.swift @@ -16,7 +16,7 @@ class VersionExtractor { public static func from(_ string: String) -> String? { do { let regex = try NSRegularExpression( - pattern: #"Laravel Valet (?(\d+)(.)(\d+)((.)(\d+))?)"#, + pattern: #"(?(\d+)(.)(\d+)((.)(\d+))?)"#, options: [] ) diff --git a/phpmon-common/PHP/ActivePhpInstallation.swift b/phpmon/Common/PHP/ActivePhpInstallation.swift similarity index 100% rename from phpmon-common/PHP/ActivePhpInstallation.swift rename to phpmon/Common/PHP/ActivePhpInstallation.swift diff --git a/phpmon-common/PHP/Homebrew/HomebrewPackage.swift b/phpmon/Common/PHP/Homebrew/HomebrewPackage.swift similarity index 100% rename from phpmon-common/PHP/Homebrew/HomebrewPackage.swift rename to phpmon/Common/PHP/Homebrew/HomebrewPackage.swift diff --git a/phpmon-common/PHP/Homebrew/HomebrewService.swift b/phpmon/Common/PHP/Homebrew/HomebrewService.swift similarity index 100% rename from phpmon-common/PHP/Homebrew/HomebrewService.swift rename to phpmon/Common/PHP/Homebrew/HomebrewService.swift diff --git a/phpmon-common/PHP/PHP Version/PhpEnv.swift b/phpmon/Common/PHP/PHP Version/PhpEnv.swift similarity index 96% rename from phpmon-common/PHP/PHP Version/PhpEnv.swift rename to phpmon/Common/PHP/PHP Version/PhpEnv.swift index 3d6c159..04230e2 100644 --- a/phpmon-common/PHP/PHP Version/PhpEnv.swift +++ b/phpmon/Common/PHP/PHP Version/PhpEnv.swift @@ -8,11 +8,6 @@ import Foundation -protocol PhpSwitcherDelegate: AnyObject { - func switcherDidStartSwitching() - func switcherDidCompleteSwitch() -} - class PhpEnv { // MARK: - Initializer @@ -161,7 +156,7 @@ class PhpEnv { */ public func validate(_ version: String) -> Bool { if self.currentInstall.version.short == version { - print("Switching to version \(version) seems to have succeeded. Validation passed.") + Log.info("Switching to version \(version) seems to have succeeded. Validation passed.") return true } diff --git a/phpmon-common/PHP/PHP Version/PhpVersionNumber.swift b/phpmon/Common/PHP/PHP Version/PhpVersionNumber.swift similarity index 96% rename from phpmon-common/PHP/PHP Version/PhpVersionNumber.swift rename to phpmon/Common/PHP/PHP Version/PhpVersionNumber.swift index 624e829..5f4c352 100644 --- a/phpmon-common/PHP/PHP Version/PhpVersionNumber.swift +++ b/phpmon/Common/PHP/PHP Version/PhpVersionNumber.swift @@ -118,6 +118,14 @@ public struct PhpVersionNumber: Equatable { */ } + public static func parse(_ text: String) throws -> Self { + guard let versionText = VersionExtractor.from(text) else { + throw VersionParseError() + } + + return Self.make(from: versionText)! + } + public static func make(from versionString: String, type: MatchType = .versionOnly) -> Self? { let regex = try! NSRegularExpression(pattern: type.rawValue, options: []) let match = regex.matches(in: versionString, options: [], range: NSMakeRange(0, versionString.count)).first diff --git a/phpmon-common/PHP/PhpExtension.swift b/phpmon/Common/PHP/PhpExtension.swift similarity index 100% rename from phpmon-common/PHP/PhpExtension.swift rename to phpmon/Common/PHP/PhpExtension.swift diff --git a/phpmon-common/PHP/PhpInstallation.swift b/phpmon/Common/PHP/PhpInstallation.swift similarity index 73% rename from phpmon-common/PHP/PhpInstallation.swift rename to phpmon/Common/PHP/PhpInstallation.swift index 4ecc010..f36fde1 100644 --- a/phpmon-common/PHP/PhpInstallation.swift +++ b/phpmon/Common/PHP/PhpInstallation.swift @@ -27,9 +27,10 @@ class PhpInstallation { arguments: ["--version"] ).trimmingCharacters(in: .whitespacesAndNewlines) - self.longVersion = PhpVersionNumber.make( - from: String(longVersionString.split(separator: "-")[0]) - )! + // 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/InternalSwitcher.swift b/phpmon/Common/PHP/Switcher/InternalSwitcher.swift similarity index 100% rename from phpmon-common/PHP/Switcher/InternalSwitcher.swift rename to phpmon/Common/PHP/Switcher/InternalSwitcher.swift diff --git a/phpmon-common/PHP/Switcher/PhpSwitcher.swift b/phpmon/Common/PHP/Switcher/PhpSwitcher.swift similarity index 65% rename from phpmon-common/PHP/Switcher/PhpSwitcher.swift rename to phpmon/Common/PHP/Switcher/PhpSwitcher.swift index e167e15..324bcde 100644 --- a/phpmon-common/PHP/Switcher/PhpSwitcher.swift +++ b/phpmon/Common/PHP/Switcher/PhpSwitcher.swift @@ -8,6 +8,14 @@ import Foundation +protocol PhpSwitcherDelegate: AnyObject { + + func switcherDidStartSwitching(to: String) + + func switcherDidCompleteSwitch(to: String) + +} + protocol PhpSwitcher { func performSwitch(to version: String, completion: @escaping () -> Void) diff --git a/phpmon/Domain/Core/App+ActivationPolicy.swift b/phpmon/Domain/App/App+ActivationPolicy.swift similarity index 100% rename from phpmon/Domain/Core/App+ActivationPolicy.swift rename to phpmon/Domain/App/App+ActivationPolicy.swift diff --git a/phpmon/Domain/Core/App+GlobalHotkey.swift b/phpmon/Domain/App/App+GlobalHotkey.swift similarity index 100% rename from phpmon/Domain/Core/App+GlobalHotkey.swift rename to phpmon/Domain/App/App+GlobalHotkey.swift diff --git a/phpmon/Domain/Core/App.swift b/phpmon/Domain/App/App.swift similarity index 83% rename from phpmon/Domain/Core/App.swift rename to phpmon/Domain/App/App.swift index c41fbd2..ae76d89 100644 --- a/phpmon/Domain/Core/App.swift +++ b/phpmon/Domain/App/App.swift @@ -8,7 +8,7 @@ import Cocoa import HotKey -class App: PhpSwitcherDelegate { +class App { // MARK: Static Vars @@ -73,20 +73,4 @@ class App: PhpSwitcherDelegate { The `PhpConfigWatcher` is responsible for watching the `.ini` files and the `.conf.d` folder. */ var watcher: PhpConfigWatcher! - - // MARK: - PhpSwitcherDelegate - - func switcherDidStartSwitching() { - } - - func switcherDidCompleteSwitch() { - PhpEnv.shared.currentInstall = ActivePhpInstallation() - handlePhpConfigWatcher() - - if let window = siteListWindowController { - DispatchQueue.main.async { - window.contentVC.reloadSites() - } - } - } } diff --git a/phpmon/Domain/Core/AppDelegate+InterApp.swift b/phpmon/Domain/App/AppDelegate+InterApp.swift similarity index 100% rename from phpmon/Domain/Core/AppDelegate+InterApp.swift rename to phpmon/Domain/App/AppDelegate+InterApp.swift diff --git a/phpmon/Domain/Core/AppDelegate+MenuOutlets.swift b/phpmon/Domain/App/AppDelegate+MenuOutlets.swift similarity index 100% rename from phpmon/Domain/Core/AppDelegate+MenuOutlets.swift rename to phpmon/Domain/App/AppDelegate+MenuOutlets.swift diff --git a/phpmon/Domain/Core/AppDelegate+Notifications.swift b/phpmon/Domain/App/AppDelegate+Notifications.swift similarity index 100% rename from phpmon/Domain/Core/AppDelegate+Notifications.swift rename to phpmon/Domain/App/AppDelegate+Notifications.swift diff --git a/phpmon/Domain/Core/AppDelegate.swift b/phpmon/Domain/App/AppDelegate.swift similarity index 88% rename from phpmon/Domain/Core/AppDelegate.swift rename to phpmon/Domain/App/AppDelegate.swift index 3b50045..fbca312 100644 --- a/phpmon/Domain/Core/AppDelegate.swift +++ b/phpmon/Domain/App/AppDelegate.swift @@ -45,12 +45,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele let valet: Valet /** - The PhpSwitcher singleton that handles PHP version + The PhpEnv singleton that handles PHP version detection, as well as switching. It is initialized when the app is ready and passed all checks. */ - var switcher: PhpEnv! = nil + var phpEnvironment: PhpEnv! = nil + /** + The logger is responsible for different levels of logging. + You can tweak the verbosity in the `init` method here. + */ var logger = Log.shared // MARK: - Initializer @@ -59,7 +63,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele When the application initializes, create all singletons. */ override init() { - logger.verbosity = .performance + logger.verbosity = .info Log.info("==================================") Log.info("PHP MONITOR by Nico Verbruggen") Log.info("Version \(App.version)") @@ -73,8 +77,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele } func initializeSwitcher() { - self.switcher = PhpEnv.shared - self.switcher.delegate = self.state + self.phpEnvironment = PhpEnv.shared } // MARK: - Lifecycle diff --git a/phpmon/Domain/Core/Base.lproj/Main.storyboard b/phpmon/Domain/App/Base.lproj/Main.storyboard similarity index 99% rename from phpmon/Domain/Core/Base.lproj/Main.storyboard rename to phpmon/Domain/App/Base.lproj/Main.storyboard index e65e6f7..bebb3da 100644 --- a/phpmon/Domain/Core/Base.lproj/Main.storyboard +++ b/phpmon/Domain/App/Base.lproj/Main.storyboard @@ -771,7 +771,7 @@ Gw