Compare commits
122 Commits
Author | SHA1 | Date | |
---|---|---|---|
507d4785aa | |||
c645bb7610 | |||
e6574966da | |||
1e9cfff05e | |||
bd34c2b255 | |||
c040ac3200 | |||
6c6888c9cb | |||
78cb6922b3 | |||
c16377c688 | |||
540ea5c310 | |||
4ba2b25f18 | |||
81b75dcaa8 | |||
884784d024 | |||
e81ff2870d | |||
7c631099b2 | |||
f7a98b88a7 | |||
3fc21fff2a | |||
0306c2b726 | |||
9d822df54e | |||
f413b84a45 | |||
b82811e6bf | |||
af922664ab | |||
8b73e69495 | |||
29a9e14741 | |||
997fb27596 | |||
c171df0a93 | |||
1c15a4e07f | |||
5067c7b87f | |||
2987464da8 | |||
4d04275c57 | |||
790f63e8c9 | |||
86b49812c3 | |||
ef9e0fd916 | |||
af8807f799 | |||
4eea13f059 | |||
ba93ed93e4 | |||
932a0fe176 | |||
3cff2d6469 | |||
df506e4128 | |||
eb80214785 | |||
80a4e361a4 | |||
2af88b2bee | |||
5048ccab8c | |||
66d13c92d5 | |||
836b076da9 | |||
1a75838a3b | |||
a18b7962a7 | |||
84548634ec | |||
419ebe61f7 | |||
c45817b127 | |||
2c0c0c5a11 | |||
1b8d6311ba | |||
f0f7a3f7d6 | |||
8304d774c3 | |||
faeea4e866 | |||
6470daf7d3 | |||
94139a3669 | |||
f3b1172d0e | |||
8057019898 | |||
9b59fc5dae | |||
75f4377de8 | |||
d3657716c4 | |||
a13990b96f | |||
4c7aa7fead | |||
32278533bf | |||
39908f7fc5 | |||
347d79c88d | |||
9bc117e9f5 | |||
ba5fbed9be | |||
211556d5ce | |||
066d7bc217 | |||
f072ceae37 | |||
273dac1ca7 | |||
f3b170ba14 | |||
78d8030ed6 | |||
a300d2f4cf | |||
96a658073e | |||
8395ba407d | |||
f80e3fed2b | |||
b48edf7409 | |||
e0a0eb089d | |||
60b126333d | |||
649a3f4fb5 | |||
9a326928f3 | |||
52f87ca18a | |||
ad2d2cb57f | |||
22c0021ada | |||
2cfc5731fb | |||
1d74e1536c | |||
e6b2ddf2ad | |||
62fda6224e | |||
083f8ebec8 | |||
aec8fb1168 | |||
d5d9b38ed6 | |||
9a6975e3d9 | |||
d1c40f2eb5 | |||
ad58661449 | |||
1d6cfd419e | |||
15182ea15a | |||
c43e00c88d | |||
25c7004368 | |||
02ba57cd64 | |||
c2dc6302c0 | |||
af9f30a123 | |||
28c5754800 | |||
48c1d48573 | |||
582bf0e12c | |||
46b30bbff4 | |||
372011ca08 | |||
7255792910 | |||
0c96b11b05 | |||
ea4da12d3b | |||
8419ebad10 | |||
09a5cf836a | |||
1a1a53b472 | |||
a8bad8447a | |||
ca8f5a8fbe | |||
a0e7aec228 | |||
26badc759e | |||
e21c2168ea | |||
589ab3664e | |||
48b4f9b160 |
15
.swiftlint.yml
Normal file
@ -0,0 +1,15 @@
|
||||
disabled_rules:
|
||||
- todo
|
||||
- identifier_name
|
||||
- force_try
|
||||
- force_cast
|
||||
|
||||
opt_in_rules:
|
||||
- empty_count
|
||||
|
||||
included:
|
||||
- phpmon
|
||||
- phpmon-tests
|
||||
|
||||
excluded:
|
||||
- phpmon/Vendor
|
14
DEVELOPER.md
@ -1,5 +1,19 @@
|
||||
# DEVELOPER README
|
||||
|
||||
## ✅ Linting
|
||||
|
||||
This project uses the [SwiftLint](https://github.com/realm/SwiftLint) linter. You must install it and can run it like so:
|
||||
|
||||
```
|
||||
swiftlint
|
||||
```
|
||||
|
||||
It also automatically runs when you try to build the project. You'll get a warning if `swiftlint` is not installed, though. You can attempt to automatically fix issues:
|
||||
|
||||
```
|
||||
swiftlint --fix
|
||||
```
|
||||
|
||||
## 🔧 Build instructions
|
||||
|
||||
<img src="./docs/build.png" width="404px" alt="build button in Xcode"/>
|
||||
|
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Nico Verbruggen
|
||||
Copyright (c) 2019-2022 Nico Verbruggen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -3,14 +3,25 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 52;
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* 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 */; };
|
||||
54A18D40282A566E000A0D81 /* nginx-secure-proxy-custom-tld.test in Resources */ = {isa = PBXBuildFile; fileRef = 54A18D3F282A566E000A0D81 /* nginx-secure-proxy-custom-tld.test */; };
|
||||
54B48B5F275F66AE006D90C5 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B48B5E275F66AE006D90C5 /* Application.swift */; };
|
||||
54B48B60275F66AE006D90C5 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B48B5E275F66AE006D90C5 /* Application.swift */; };
|
||||
54D9E0B227E4F51E003B9AD9 /* HotKeysController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0AC27E4F51E003B9AD9 /* HotKeysController.swift */; };
|
||||
54D9E0B327E4F51E003B9AD9 /* HotKeysController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0AC27E4F51E003B9AD9 /* HotKeysController.swift */; };
|
||||
54D9E0B427E4F51E003B9AD9 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0AD27E4F51E003B9AD9 /* Key.swift */; };
|
||||
54D9E0B527E4F51E003B9AD9 /* Key.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0AD27E4F51E003B9AD9 /* Key.swift */; };
|
||||
54D9E0B627E4F51E003B9AD9 /* HotKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0AE27E4F51E003B9AD9 /* HotKey.swift */; };
|
||||
54D9E0B727E4F51E003B9AD9 /* HotKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0AE27E4F51E003B9AD9 /* HotKey.swift */; };
|
||||
54D9E0B827E4F51E003B9AD9 /* KeyCombo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0AF27E4F51E003B9AD9 /* KeyCombo.swift */; };
|
||||
54D9E0B927E4F51E003B9AD9 /* KeyCombo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0AF27E4F51E003B9AD9 /* KeyCombo.swift */; };
|
||||
54D9E0BA27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0B027E4F51E003B9AD9 /* ModifierFlagsExtension.swift */; };
|
||||
54D9E0BB27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D9E0B027E4F51E003B9AD9 /* ModifierFlagsExtension.swift */; };
|
||||
54EAC806262F212B0092D14E /* GlobalKeybindPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */; };
|
||||
54FCFD26276C883F004CE748 /* SelectPreferenceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54FCFD25276C883F004CE748 /* SelectPreferenceView.xib */; };
|
||||
54FCFD27276C883F004CE748 /* SelectPreferenceView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54FCFD25276C883F004CE748 /* SelectPreferenceView.xib */; };
|
||||
@ -41,6 +52,9 @@
|
||||
C40C7F2927721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */; };
|
||||
C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2F27722E8D00DDDCDC /* Logger.swift */; };
|
||||
C40C7F3127722E8D00DDDCDC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2F27722E8D00DDDCDC /* Logger.swift */; };
|
||||
C40FE737282ABA4F00A302C2 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE736282ABA4F00A302C2 /* AppVersion.swift */; };
|
||||
C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE736282ABA4F00A302C2 /* AppVersion.swift */; };
|
||||
C40FE73B282ABB2E00A302C2 /* AppVersionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE739282ABB2E00A302C2 /* AppVersionTest.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 */; };
|
||||
@ -52,25 +66,47 @@
|
||||
C417DC75277614690015E6EE /* 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 */; };
|
||||
C41C02A627E60D7A009F26CB /* SiteScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C02A527E60D7A009F26CB /* SiteScanner.swift */; };
|
||||
C41C02A927E61A65009F26CB /* ValetSite+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C02A827E61A65009F26CB /* ValetSite+Fake.swift */; };
|
||||
C41C02AA27E61CA3009F26CB /* SiteScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C02A527E60D7A009F26CB /* SiteScanner.swift */; };
|
||||
C41C02AB27E61CB3009F26CB /* ValetSite+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C02A827E61A65009F26CB /* ValetSite+Fake.swift */; };
|
||||
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */; };
|
||||
C41C1B3B22B0098000E7CF16 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3A22B0098000E7CF16 /* Assets.xcassets */; };
|
||||
C41C1B3E22B0098000E7CF16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3C22B0098000E7CF16 /* Main.storyboard */; };
|
||||
C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */; };
|
||||
C41C1B4B22B019FF00E7CF16 /* ActivePhpInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4A22B019FF00E7CF16 /* ActivePhpInstallation.swift */; };
|
||||
C41CA5ED2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CA5EC2774F8EE00A2C80E /* SiteListVC+Actions.swift */; };
|
||||
C41CA5EE2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CA5EC2774F8EE00A2C80E /* SiteListVC+Actions.swift */; };
|
||||
C41CA5ED2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CA5EC2774F8EE00A2C80E /* DomainListVC+Actions.swift */; };
|
||||
C41CA5EE2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CA5EC2774F8EE00A2C80E /* DomainListVC+Actions.swift */; };
|
||||
C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */; };
|
||||
C41E871A2763D42300161EE0 /* SiteListVC+ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41E87192763D42300161EE0 /* SiteListVC+ContextMenu.swift */; };
|
||||
C41E871B2763D42300161EE0 /* SiteListVC+ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41E87192763D42300161EE0 /* SiteListVC+ContextMenu.swift */; };
|
||||
C41E871A2763D42300161EE0 /* DomainListVC+ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41E87192763D42300161EE0 /* DomainListVC+ContextMenu.swift */; };
|
||||
C41E871B2763D42300161EE0 /* DomainListVC+ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41E87192763D42300161EE0 /* DomainListVC+ContextMenu.swift */; };
|
||||
C4205A7E27F4D21800191A39 /* ValetProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4205A7D27F4D21800191A39 /* ValetProxy.swift */; };
|
||||
C4205A7F27F4D21800191A39 /* ValetProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4205A7D27F4D21800191A39 /* ValetProxy.swift */; };
|
||||
C4232EE52612526500158FC6 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = C4232EE42612526500158FC6 /* Credits.html */; };
|
||||
C42337A3281F19F000459A48 /* Xdebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42337A2281F19F000459A48 /* Xdebug.swift */; };
|
||||
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 */; };
|
||||
C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1527DFDE7900862737 /* nginx-site.test */; };
|
||||
C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */; };
|
||||
C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */; };
|
||||
C42F26732805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; };
|
||||
C42F26742805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; };
|
||||
C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */; };
|
||||
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 */; };
|
||||
C43A8A2025D9D1D700591B77 /* brew.json in Resources */ = {isa = PBXBuildFile; fileRef = C43A8A1F25D9D1D700591B77 /* brew.json */; };
|
||||
C43A8A2425D9D20D00591B77 /* BrewJsonParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43A8A2325D9D20D00591B77 /* BrewJsonParserTest.swift */; };
|
||||
C43A8A2025D9D1D700591B77 /* brew-formula.json in Resources */ = {isa = PBXBuildFile; fileRef = C43A8A1F25D9D1D700591B77 /* brew-formula.json */; };
|
||||
C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */; };
|
||||
C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F427E2582B0045BD4E /* DomainListNameCell.swift */; };
|
||||
C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F627E258410045BD4E /* DomainListPhpCell.swift */; };
|
||||
C44067F927E2585E0045BD4E /* DomainListTypeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */; };
|
||||
C44067FB27E25FD70045BD4E /* DomainListTLSCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */; };
|
||||
C449B4F027EE7FB800C47E8A /* DomainListTLSCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */; };
|
||||
C449B4F127EE7FC200C47E8A /* DomainListNameCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F427E2582B0045BD4E /* DomainListNameCell.swift */; };
|
||||
C449B4F227EE7FC400C47E8A /* DomainListPhpCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F627E258410045BD4E /* DomainListPhpCell.swift */; };
|
||||
C449B4F327EE7FC600C47E8A /* DomainListTypeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */; };
|
||||
C449B4F427EE7FC800C47E8A /* DomainListKindCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AC51FB27E27F47008528CA /* DomainListKindCell.swift */; };
|
||||
C44C198D276E3A1C0072762D /* ProgressWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* ProgressWindow.swift */; };
|
||||
C44C198E276E3A1C0072762D /* ProgressWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* ProgressWindow.swift */; };
|
||||
C44C1991276E44CB0072762D /* ProgressWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C44C1990276E44CB0072762D /* ProgressWindow.storyboard */; };
|
||||
@ -79,12 +115,15 @@
|
||||
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 */; };
|
||||
C464ADB0275A7A6A003FCD53 /* SiteListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAE275A7A69003FCD53 /* SiteListVC.swift */; };
|
||||
C464ADB2275A87CA003FCD53 /* SiteListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADB1275A87CA003FCD53 /* SiteListCell.swift */; };
|
||||
C464ADB3275A87CA003FCD53 /* SiteListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADB1275A87CA003FCD53 /* SiteListCell.swift */; };
|
||||
C459B4BD27F6093700E9B4B4 /* nginx-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C459B4BC27F6093700E9B4B4 /* nginx-proxy.test */; };
|
||||
C464ADAC275A7A3F003FCD53 /* DomainListWC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAB275A7A3F003FCD53 /* DomainListWC.swift */; };
|
||||
C464ADAD275A7A3F003FCD53 /* DomainListWC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAB275A7A3F003FCD53 /* DomainListWC.swift */; };
|
||||
C464ADAF275A7A69003FCD53 /* DomainListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAE275A7A69003FCD53 /* DomainListVC.swift */; };
|
||||
C464ADB0275A7A6A003FCD53 /* DomainListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAE275A7A69003FCD53 /* DomainListVC.swift */; };
|
||||
C464ADB2275A87CA003FCD53 /* DomainListCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADB1275A87CA003FCD53 /* DomainListCellProtocol.swift */; };
|
||||
C46E206D28299B3800D909D6 /* AppUpdateChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */; };
|
||||
C46E206E28299B3800D909D6 /* AppUpdateChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */; };
|
||||
C46E20702829D27F00D909D6 /* AppUpdaterCheckTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46E206F2829D27F00D909D6 /* AppUpdaterCheckTest.swift */; };
|
||||
C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA23E246C358E00944F05 /* StringExtension.swift */; };
|
||||
C473319F2470923A009A0597 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C473319E2470923A009A0597 /* Localizable.strings */; };
|
||||
C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47331A1247093B7009A0597 /* StatusMenu.swift */; };
|
||||
@ -94,6 +133,8 @@
|
||||
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */; };
|
||||
C481F79726164A78004FBCFF /* PrefsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395826135DC100FB00FA /* PrefsVC.swift */; };
|
||||
C481F79A26164A7C004FBCFF /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395E2613607600FB00FA /* Preferences.swift */; };
|
||||
C484437B2804BB560041A78A /* ValetProxyScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C484437A2804BB560041A78A /* ValetProxyScanner.swift */; };
|
||||
C484437C2804BB560041A78A /* ValetProxyScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C484437A2804BB560041A78A /* ValetProxyScanner.swift */; };
|
||||
C48D0C9025CC7FD000CC7490 /* StatsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C48D0C8F25CC7FD000CC7490 /* StatsView.xib */; };
|
||||
C48D0C9325CC804200CC7490 /* XibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0C9225CC804200CC7490 /* XibLoadable.swift */; };
|
||||
C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0C9525CC80B100CC7490 /* HeaderView.swift */; };
|
||||
@ -106,14 +147,14 @@
|
||||
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 */; };
|
||||
C4998F0A2617633900B2526E /* PrefsWC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4998F092617633900B2526E /* PrefsWC.swift */; };
|
||||
C4998F0B2617633900B2526E /* PrefsWC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4998F092617633900B2526E /* PrefsWC.swift */; };
|
||||
C49E171F27A5736E00787921 /* PMServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49E171E27A5736E00787921 /* PMServicesView.swift */; };
|
||||
C4AC51FC27E27F47008528CA /* DomainListKindCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AC51FB27E27F47008528CA /* DomainListKindCell.swift */; };
|
||||
C4ACA38F25C754C100060C66 /* PhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4ACA38E25C754C100060C66 /* PhpExtension.swift */; };
|
||||
C4AF9F71275445FF00D44ED0 /* valet-config.json in Resources */ = {isa = PBXBuildFile; fileRef = C4AF9F70275445FF00D44ED0 /* valet-config.json */; };
|
||||
C4AF9F72275445FF00D44ED0 /* valet-config.json in Resources */ = {isa = PBXBuildFile; fileRef = C4AF9F70275445FF00D44ED0 /* valet-config.json */; };
|
||||
C4AF9F78275447F100D44ED0 /* ValetConfigParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F76275447F100D44ED0 /* ValetConfigParserTest.swift */; };
|
||||
C4AF9F78275447F100D44ED0 /* ValetConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F76275447F100D44ED0 /* ValetConfigurationTest.swift */; };
|
||||
C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F792754499000D44ED0 /* Valet.swift */; };
|
||||
C4AF9F7B2754499000D44ED0 /* Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F792754499000D44ED0 /* Valet.swift */; };
|
||||
C4AF9F7D275454A900D44ED0 /* ValetVersionExtractorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F7C275454A900D44ED0 /* ValetVersionExtractorTest.swift */; };
|
||||
@ -133,7 +174,14 @@
|
||||
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 */; };
|
||||
C4C0E8DF27F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C0E8DE27F88AEB002D32A9 /* FakeSiteScanner.swift */; };
|
||||
C4C0E8E027F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C0E8DE27F88AEB002D32A9 /* FakeSiteScanner.swift */; };
|
||||
C4C0E8E227F88B13002D32A9 /* ValetSiteScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C0E8E127F88B13002D32A9 /* ValetSiteScanner.swift */; };
|
||||
C4C0E8E327F88B13002D32A9 /* ValetSiteScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C0E8E127F88B13002D32A9 /* ValetSiteScanner.swift */; };
|
||||
C4C0E8E727F88B41002D32A9 /* ProxyScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C0E8E627F88B41002D32A9 /* ProxyScanner.swift */; };
|
||||
C4C0E8E827F88B41002D32A9 /* ProxyScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C0E8E627F88B41002D32A9 /* ProxyScanner.swift */; };
|
||||
C4C0E8EA27F88B80002D32A9 /* ValetProxy+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C0E8E927F88B80002D32A9 /* ValetProxy+Fake.swift */; };
|
||||
C4C0E8EB27F88B80002D32A9 /* ValetProxy+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C0E8E927F88B80002D32A9 /* ValetProxy+Fake.swift */; };
|
||||
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 */; };
|
||||
@ -148,12 +196,19 @@
|
||||
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 /* ComposerWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */; };
|
||||
C4D5CFCA27E0F9CD00035329 /* NginxConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfiguration.swift */; };
|
||||
C4D5CFCB27E0F9CD00035329 /* NginxConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfiguration.swift */; };
|
||||
C4D8016622B1584700C6DA1B /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
|
||||
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; };
|
||||
C4D936C927E3EB6100BD69FE /* PhpHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D936C827E3EB6100BD69FE /* PhpHelper.swift */; };
|
||||
C4D936CA27E3EB6100BD69FE /* PhpHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D936C827E3EB6100BD69FE /* PhpHelper.swift */; };
|
||||
C4D936CB27E3EE4A00BD69FE /* DomainListCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADB1275A87CA003FCD53 /* DomainListCellProtocol.swift */; };
|
||||
C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */; };
|
||||
C4D9ADC0277610E1007277F4 /* 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 */; };
|
||||
C4D9F24B280B69E100DCD39A /* AddProxyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9F24A280B69E100DCD39A /* AddProxyVC.swift */; };
|
||||
C4D9F24C280B69E100DCD39A /* AddProxyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9F24A280B69E100DCD39A /* AddProxyVC.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 */; };
|
||||
@ -182,9 +237,10 @@
|
||||
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 */; };
|
||||
C4F5FBCD28218CB8001065C5 /* Xdebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42337A2281F19F000459A48 /* Xdebug.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 */; };
|
||||
C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F780AD25D80B37000DBC97 /* PhpExtensionTest.swift */; };
|
||||
C4F780B125D80B4D000DBC97 /* PhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4ACA38E25C754C100060C66 /* PhpExtension.swift */; };
|
||||
C4F780B725D80B5D000DBC97 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2322D70A4700B5F6B3 /* App.swift */; };
|
||||
C4F780BA25D80B62000DBC97 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */; };
|
||||
@ -203,6 +259,8 @@
|
||||
C4F780CE25D80B75000DBC97 /* LocalNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = C474B00524C0E98C00066A22 /* LocalNotification.swift */; };
|
||||
C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8C0A322D4F12C002EFE61 /* DateExtension.swift */; };
|
||||
C4FBFC532616485F00CDB8E1 /* PhpVersionDetectionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FBFC512616485F00CDB8E1 /* PhpVersionDetectionTest.swift */; };
|
||||
C4FE011128084FC200D1DE6D /* SelectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FE011028084FC200D1DE6D /* SelectionVC.swift */; };
|
||||
C4FE011228084FC200D1DE6D /* SelectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FE011028084FC200D1DE6D /* SelectionVC.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -218,7 +276,15 @@
|
||||
/* Begin PBXFileReference section */
|
||||
5420395826135DC100FB00FA /* PrefsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsVC.swift; sourceTree = "<group>"; };
|
||||
5420395E2613607600FB00FA /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
|
||||
54A18D3F282A566E000A0D81 /* nginx-secure-proxy-custom-tld.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-secure-proxy-custom-tld.test"; sourceTree = "<group>"; };
|
||||
54B48B5E275F66AE006D90C5 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
||||
54D9E0AC27E4F51E003B9AD9 /* HotKeysController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HotKeysController.swift; sourceTree = "<group>"; };
|
||||
54D9E0AD27E4F51E003B9AD9 /* Key.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Key.swift; sourceTree = "<group>"; };
|
||||
54D9E0AE27E4F51E003B9AD9 /* HotKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HotKey.swift; sourceTree = "<group>"; };
|
||||
54D9E0AF27E4F51E003B9AD9 /* KeyCombo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyCombo.swift; sourceTree = "<group>"; };
|
||||
54D9E0B027E4F51E003B9AD9 /* ModifierFlagsExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModifierFlagsExtension.swift; sourceTree = "<group>"; };
|
||||
54D9E0BF27E4F5D9003B9AD9 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
54D9E0C027E4F5E9003B9AD9 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
54FCFD25276C883F004CE748 /* SelectPreferenceView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SelectPreferenceView.xib; sourceTree = "<group>"; };
|
||||
54FCFD29276C8AA4004CE748 /* CheckboxPreferenceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxPreferenceView.swift; sourceTree = "<group>"; };
|
||||
54FCFD2C276C8D67004CE748 /* HotkeyPreferenceView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HotkeyPreferenceView.xib; sourceTree = "<group>"; };
|
||||
@ -233,6 +299,8 @@
|
||||
C40C7F1D2772136000DDDCDC /* PhpEnv.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpEnv.swift; sourceTree = "<group>"; };
|
||||
C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActivePhpInstallation+Checks.swift"; sourceTree = "<group>"; };
|
||||
C40C7F2F27722E8D00DDDCDC /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
|
||||
C40FE736282ABA4F00A302C2 /* AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = "<group>"; };
|
||||
C40FE739282ABB2E00A302C2 /* AppVersionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersionTest.swift; sourceTree = "<group>"; };
|
||||
C412E5FB25700D5300A1FB67 /* HomebrewPackage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewPackage.swift; sourceTree = "<group>"; };
|
||||
C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpFrameworks.swift; sourceTree = "<group>"; };
|
||||
C415D3B62770F294005EF286 /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = "<group>"; };
|
||||
@ -240,6 +308,8 @@
|
||||
C4168F4427ADB4A3003B6C39 /* DEVELOPER.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = DEVELOPER.md; sourceTree = "<group>"; };
|
||||
C417DC73277614690015E6EE /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
|
||||
C4188988275FE8CB001EF227 /* Filesystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filesystem.swift; sourceTree = "<group>"; };
|
||||
C41C02A527E60D7A009F26CB /* SiteScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteScanner.swift; sourceTree = "<group>"; };
|
||||
C41C02A827E61A65009F26CB /* ValetSite+Fake.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ValetSite+Fake.swift"; sourceTree = "<group>"; };
|
||||
C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PHP Monitor.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
C41C1B3A22B0098000E7CF16 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
@ -248,23 +318,37 @@
|
||||
C41C1B4022B0098000E7CF16 /* phpmon.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = phpmon.entitlements; sourceTree = "<group>"; };
|
||||
C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarImageGenerator.swift; sourceTree = "<group>"; };
|
||||
C41C1B4A22B019FF00E7CF16 /* ActivePhpInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivePhpInstallation.swift; sourceTree = "<group>"; };
|
||||
C41CA5EC2774F8EE00A2C80E /* SiteListVC+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SiteListVC+Actions.swift"; sourceTree = "<group>"; };
|
||||
C41CA5EC2774F8EE00A2C80E /* DomainListVC+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DomainListVC+Actions.swift"; sourceTree = "<group>"; };
|
||||
C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalKeybindPreference.swift; sourceTree = "<group>"; };
|
||||
C41E87192763D42300161EE0 /* SiteListVC+ContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SiteListVC+ContextMenu.swift"; sourceTree = "<group>"; };
|
||||
C41E87192763D42300161EE0 /* DomainListVC+ContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DomainListVC+ContextMenu.swift"; sourceTree = "<group>"; };
|
||||
C4205A7D27F4D21800191A39 /* ValetProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetProxy.swift; sourceTree = "<group>"; };
|
||||
C4232EE42612526500158FC6 /* Credits.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = Credits.html; sourceTree = "<group>"; };
|
||||
C42337A2281F19F000459A48 /* Xdebug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Xdebug.swift; sourceTree = "<group>"; };
|
||||
C42759662627662800093CAE /* NSMenuExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSMenuExtension.swift; sourceTree = "<group>"; };
|
||||
C42C49DA27C2806F0074ABAC /* MainMenu+FixMyValet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+FixMyValet.swift"; sourceTree = "<group>"; };
|
||||
C42CFB1527DFDE7900862737 /* nginx-site.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site.test"; sourceTree = "<group>"; };
|
||||
C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site-isolated.test"; sourceTree = "<group>"; };
|
||||
C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfigurationTest.swift; sourceTree = "<group>"; };
|
||||
C42F26722805B4B400938AC7 /* DomainListable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListable.swift; sourceTree = "<group>"; };
|
||||
C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-secure-proxy.test"; sourceTree = "<group>"; };
|
||||
C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Notifications.swift"; sourceTree = "<group>"; };
|
||||
C43A8A1925D9CD1000591B77 /* Utility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = "<group>"; };
|
||||
C43A8A1F25D9D1D700591B77 /* brew.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = brew.json; sourceTree = "<group>"; };
|
||||
C43A8A2325D9D20D00591B77 /* BrewJsonParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewJsonParserTest.swift; sourceTree = "<group>"; };
|
||||
C43A8A1F25D9D1D700591B77 /* brew-formula.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "brew-formula.json"; sourceTree = "<group>"; };
|
||||
C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewPackageTest.swift; sourceTree = "<group>"; };
|
||||
C44067F427E2582B0045BD4E /* DomainListNameCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListNameCell.swift; sourceTree = "<group>"; };
|
||||
C44067F627E258410045BD4E /* DomainListPhpCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListPhpCell.swift; sourceTree = "<group>"; };
|
||||
C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListTypeCell.swift; sourceTree = "<group>"; };
|
||||
C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListTLSCell.swift; sourceTree = "<group>"; };
|
||||
C44C198C276E3A1C0072762D /* ProgressWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressWindow.swift; sourceTree = "<group>"; };
|
||||
C44C1990276E44CB0072762D /* ProgressWindow.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ProgressWindow.storyboard; sourceTree = "<group>"; };
|
||||
C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertableError.swift; sourceTree = "<group>"; };
|
||||
C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Async.swift"; sourceTree = "<group>"; };
|
||||
C464ADAB275A7A3F003FCD53 /* SiteListWC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteListWC.swift; sourceTree = "<group>"; };
|
||||
C464ADAE275A7A69003FCD53 /* SiteListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteListVC.swift; sourceTree = "<group>"; };
|
||||
C464ADB1275A87CA003FCD53 /* SiteListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteListCell.swift; sourceTree = "<group>"; };
|
||||
C459B4BC27F6093700E9B4B4 /* nginx-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-proxy.test"; sourceTree = "<group>"; };
|
||||
C464ADAB275A7A3F003FCD53 /* DomainListWC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListWC.swift; sourceTree = "<group>"; };
|
||||
C464ADAE275A7A69003FCD53 /* DomainListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListVC.swift; sourceTree = "<group>"; };
|
||||
C464ADB1275A87CA003FCD53 /* DomainListCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListCellProtocol.swift; sourceTree = "<group>"; };
|
||||
C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateChecker.swift; sourceTree = "<group>"; };
|
||||
C46E206F2829D27F00D909D6 /* AppUpdaterCheckTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUpdaterCheckTest.swift; sourceTree = "<group>"; };
|
||||
C46FA23E246C358E00944F05 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = "<group>"; };
|
||||
C473319E2470923A009A0597 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
C47331A1247093B7009A0597 /* StatusMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusMenu.swift; sourceTree = "<group>"; };
|
||||
@ -272,6 +356,7 @@
|
||||
C476FF9722B0DD830098105B /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = "<group>"; };
|
||||
C4811D2322D70A4700B5F6B3 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
|
||||
C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
|
||||
C484437A2804BB560041A78A /* ValetProxyScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetProxyScanner.swift; sourceTree = "<group>"; };
|
||||
C48D0C8F25CC7FD000CC7490 /* StatsView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StatsView.xib; sourceTree = "<group>"; };
|
||||
C48D0C9225CC804200CC7490 /* XibLoadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XibLoadable.swift; sourceTree = "<group>"; };
|
||||
C48D0C9525CC80B100CC7490 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = "<group>"; };
|
||||
@ -283,9 +368,10 @@
|
||||
C4930849279F331F009C240B /* AddSiteVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSiteVC.swift; sourceTree = "<group>"; };
|
||||
C4998F092617633900B2526E /* PrefsWC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsWC.swift; sourceTree = "<group>"; };
|
||||
C49E171E27A5736E00787921 /* PMServicesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PMServicesView.swift; sourceTree = "<group>"; };
|
||||
C4AC51FB27E27F47008528CA /* DomainListKindCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListKindCell.swift; sourceTree = "<group>"; };
|
||||
C4ACA38E25C754C100060C66 /* PhpExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpExtension.swift; sourceTree = "<group>"; };
|
||||
C4AF9F70275445FF00D44ED0 /* valet-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "valet-config.json"; sourceTree = "<group>"; };
|
||||
C4AF9F76275447F100D44ED0 /* ValetConfigParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetConfigParserTest.swift; sourceTree = "<group>"; };
|
||||
C4AF9F76275447F100D44ED0 /* ValetConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetConfigurationTest.swift; sourceTree = "<group>"; };
|
||||
C4AF9F792754499000D44ED0 /* Valet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Valet.swift; sourceTree = "<group>"; };
|
||||
C4AF9F7C275454A900D44ED0 /* ValetVersionExtractorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetVersionExtractorTest.swift; sourceTree = "<group>"; };
|
||||
C4B5635D276AB09000F12CCB /* VersionExtractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionExtractor.swift; sourceTree = "<group>"; };
|
||||
@ -296,6 +382,10 @@
|
||||
C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+MenuOutlets.swift"; sourceTree = "<group>"; };
|
||||
C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+ActivationPolicy.swift"; sourceTree = "<group>"; };
|
||||
C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+GlobalHotkey.swift"; sourceTree = "<group>"; };
|
||||
C4C0E8DE27F88AEB002D32A9 /* FakeSiteScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeSiteScanner.swift; sourceTree = "<group>"; };
|
||||
C4C0E8E127F88B13002D32A9 /* ValetSiteScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetSiteScanner.swift; sourceTree = "<group>"; };
|
||||
C4C0E8E627F88B41002D32A9 /* ProxyScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyScanner.swift; sourceTree = "<group>"; };
|
||||
C4C0E8E927F88B80002D32A9 /* ValetProxy+Fake.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ValetProxy+Fake.swift"; sourceTree = "<group>"; };
|
||||
C4C1019A27C65C6F001FACC2 /* Process.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Process.swift; sourceTree = "<group>"; };
|
||||
C4C3ED402783497000AB15D8 /* MainMenu+Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Startup.swift"; sourceTree = "<group>"; };
|
||||
C4C3ED4227834C5200AB15D8 /* CustomPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPrefs.swift; sourceTree = "<group>"; };
|
||||
@ -304,10 +394,13 @@
|
||||
C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = "<group>"; };
|
||||
C4CE3BB727B31F2E0086CA49 /* MainMenu+Switcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Switcher.swift"; sourceTree = "<group>"; };
|
||||
C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerWindow.swift; sourceTree = "<group>"; };
|
||||
C4D5CFC927E0F9CD00035329 /* NginxConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfiguration.swift; sourceTree = "<group>"; };
|
||||
C4D8016522B1584700C6DA1B /* Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Startup.swift; sourceTree = "<group>"; };
|
||||
C4D89BC52783C99400A02B68 /* ComposerJson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerJson.swift; sourceTree = "<group>"; };
|
||||
C4D936C827E3EB6100BD69FE /* PhpHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpHelper.swift; sourceTree = "<group>"; };
|
||||
C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpSwitcher.swift; sourceTree = "<group>"; };
|
||||
C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalSwitcher.swift; sourceTree = "<group>"; };
|
||||
C4D9F24A280B69E100DCD39A /* AddProxyVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddProxyVC.swift; sourceTree = "<group>"; };
|
||||
C4DEB7D327A5D60B00834718 /* Stats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stats.swift; sourceTree = "<group>"; };
|
||||
C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSWindowExtension.swift; sourceTree = "<group>"; };
|
||||
C4E4404527C56F4700D225E1 /* ValetSite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetSite.swift; sourceTree = "<group>"; };
|
||||
@ -325,14 +418,16 @@
|
||||
C4F2E4392752F7D00020E974 /* PhpInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpInstallation.swift; sourceTree = "<group>"; };
|
||||
C4F30B02278E16BA00755FCE /* HomebrewService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewService.swift; sourceTree = "<group>"; };
|
||||
C4F30B06278E195800755FCE /* brew-services.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "brew-services.json"; sourceTree = "<group>"; };
|
||||
C4F5FBCC28218C93001065C5 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
C4F7809B25D80344000DBC97 /* CommandTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandTest.swift; sourceTree = "<group>"; };
|
||||
C4F780A725D80AE8000DBC97 /* php.ini */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = php.ini; sourceTree = "<group>"; };
|
||||
C4F780AD25D80B37000DBC97 /* ExtensionParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionParserTest.swift; sourceTree = "<group>"; };
|
||||
C4F780AD25D80B37000DBC97 /* PhpExtensionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpExtensionTest.swift; sourceTree = "<group>"; };
|
||||
C4F8C0A322D4F12C002EFE61 /* DateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtension.swift; sourceTree = "<group>"; };
|
||||
C4F8C0A522D4FA41002EFE61 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
C4FBFC512616485F00CDB8E1 /* PhpVersionDetectionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpVersionDetectionTest.swift; sourceTree = "<group>"; };
|
||||
C4FE011028084FC200D1DE6D /* SelectionVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionVC.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -340,7 +435,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C4998F0626175E7200B2526E /* HotKey in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -348,7 +442,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C4C1019627C659B7001FACC2 /* HotKey in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -376,6 +469,7 @@
|
||||
C48D6C6E279CD29C00F26D7E /* PHP Version */,
|
||||
C4D9ADC2277610E4007277F4 /* Switcher */,
|
||||
C4F30B01278E169B00755FCE /* Homebrew */,
|
||||
C42337A1281F19DC00459A48 /* Extensions */,
|
||||
C41C1B4A22B019FF00E7CF16 /* ActivePhpInstallation.swift */,
|
||||
C4F2E4392752F7D00020E974 /* PhpInstallation.swift */,
|
||||
C4ACA38E25C754C100060C66 /* PhpExtension.swift */,
|
||||
@ -383,6 +477,27 @@
|
||||
path = PHP;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
54D9E0AB27E4F502003B9AD9 /* HotKey */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
54D9E0BF27E4F5D9003B9AD9 /* LICENSE */,
|
||||
54D9E0AE27E4F51E003B9AD9 /* HotKey.swift */,
|
||||
54D9E0AC27E4F51E003B9AD9 /* HotKeysController.swift */,
|
||||
54D9E0AD27E4F51E003B9AD9 /* Key.swift */,
|
||||
54D9E0AF27E4F51E003B9AD9 /* KeyCombo.swift */,
|
||||
54D9E0B027E4F51E003B9AD9 /* ModifierFlagsExtension.swift */,
|
||||
);
|
||||
path = HotKey;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
54D9E0BE27E4F5C0003B9AD9 /* Vendor */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
54D9E0AB27E4F502003B9AD9 /* HotKey */,
|
||||
);
|
||||
path = Vendor;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
54FCFD28276C88C0004CE748 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -417,10 +532,10 @@
|
||||
C40C7F1C27720E1400DDDCDC /* Test Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4AF9F70275445FF00D44ED0 /* valet-config.json */,
|
||||
C43A8A1F25D9D1D700591B77 /* brew.json */,
|
||||
C4F30B06278E195800755FCE /* brew-services.json */,
|
||||
C4F780A725D80AE8000DBC97 /* php.ini */,
|
||||
C459B4C127F6097E00E9B4B4 /* php */,
|
||||
C459B4C027F6096300E9B4B4 /* valet */,
|
||||
C459B4BF27F6094100E9B4B4 /* brew */,
|
||||
C459B4BE27F6093A00E9B4B4 /* nginx */,
|
||||
);
|
||||
path = "Test Files";
|
||||
sourceTree = "<group>";
|
||||
@ -447,6 +562,8 @@
|
||||
C4F8C0A522D4FA41002EFE61 /* README.md */,
|
||||
C4E713562570150F00007428 /* SECURITY.md */,
|
||||
C4168F4427ADB4A3003B6C39 /* DEVELOPER.md */,
|
||||
54D9E0C027E4F5E9003B9AD9 /* LICENSE */,
|
||||
C4F5FBCC28218C93001065C5 /* .swiftlint.yml */,
|
||||
C4E713572570151400007428 /* docs */,
|
||||
C41C1B3522B0097F00E7CF16 /* phpmon */,
|
||||
C4F7807A25D7F84B000DBC97 /* phpmon-tests */,
|
||||
@ -469,6 +586,7 @@
|
||||
children = (
|
||||
C4B5853A2770FE2500DA4FBE /* Common */,
|
||||
C41E181722CB61EB0072CF09 /* Domain */,
|
||||
54D9E0BE27E4F5C0003B9AD9 /* Vendor */,
|
||||
C41C1B3F22B0098000E7CF16 /* Info.plist */,
|
||||
C4232EE42612526500158FC6 /* Credits.html */,
|
||||
C41C1B4022B0098000E7CF16 /* phpmon.entitlements */,
|
||||
@ -495,7 +613,7 @@
|
||||
C4B13B1D25C4915000548C3A /* App */,
|
||||
C4D9ADBD27761084007277F4 /* PHP */,
|
||||
C47331A0247093AC009A0597 /* Menu */,
|
||||
C464ADAA275A7A25003FCD53 /* SiteList */,
|
||||
C464ADAA275A7A25003FCD53 /* DomainList */,
|
||||
5420395726135DB800FB00FA /* Preferences */,
|
||||
C44C198F276E3A380072762D /* Progress */,
|
||||
C4C8E81D276F5686003AC782 /* Watcher */,
|
||||
@ -504,6 +622,27 @@
|
||||
path = Domain;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C42337A1281F19DC00459A48 /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C42337A2281F19F000459A48 /* Xdebug.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C44067F327E256560045BD4E /* Cells */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C464ADB1275A87CA003FCD53 /* DomainListCellProtocol.swift */,
|
||||
C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */,
|
||||
C44067F427E2582B0045BD4E /* DomainListNameCell.swift */,
|
||||
C44067F627E258410045BD4E /* DomainListPhpCell.swift */,
|
||||
C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */,
|
||||
C4AC51FB27E27F47008528CA /* DomainListKindCell.swift */,
|
||||
);
|
||||
path = Cells;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C44C198F276E3A380072762D /* Progress */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -522,17 +661,56 @@
|
||||
path = Errors;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C464ADAA275A7A25003FCD53 /* SiteList */ = {
|
||||
C459B4BE27F6093A00E9B4B4 /* nginx */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C464ADAB275A7A3F003FCD53 /* SiteListWC.swift */,
|
||||
C464ADAE275A7A69003FCD53 /* SiteListVC.swift */,
|
||||
C41E87192763D42300161EE0 /* SiteListVC+ContextMenu.swift */,
|
||||
C41CA5EC2774F8EE00A2C80E /* SiteListVC+Actions.swift */,
|
||||
C4930849279F331F009C240B /* AddSiteVC.swift */,
|
||||
C464ADB1275A87CA003FCD53 /* SiteListCell.swift */,
|
||||
C459B4BC27F6093700E9B4B4 /* nginx-proxy.test */,
|
||||
C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */,
|
||||
54A18D3F282A566E000A0D81 /* nginx-secure-proxy-custom-tld.test */,
|
||||
C42CFB1527DFDE7900862737 /* nginx-site.test */,
|
||||
C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */,
|
||||
);
|
||||
path = SiteList;
|
||||
path = nginx;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C459B4BF27F6094100E9B4B4 /* brew */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C43A8A1F25D9D1D700591B77 /* brew-formula.json */,
|
||||
C4F30B06278E195800755FCE /* brew-services.json */,
|
||||
);
|
||||
path = brew;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C459B4C027F6096300E9B4B4 /* valet */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4AF9F70275445FF00D44ED0 /* valet-config.json */,
|
||||
);
|
||||
path = valet;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C459B4C127F6097E00E9B4B4 /* php */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4F780A725D80AE8000DBC97 /* php.ini */,
|
||||
);
|
||||
path = php;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C464ADAA275A7A25003FCD53 /* DomainList */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C44067F327E256560045BD4E /* Cells */,
|
||||
C464ADAB275A7A3F003FCD53 /* DomainListWC.swift */,
|
||||
C464ADAE275A7A69003FCD53 /* DomainListVC.swift */,
|
||||
C41E87192763D42300161EE0 /* DomainListVC+ContextMenu.swift */,
|
||||
C41CA5EC2774F8EE00A2C80E /* DomainListVC+Actions.swift */,
|
||||
C4FE011028084FC200D1DE6D /* SelectionVC.swift */,
|
||||
C4930849279F331F009C240B /* AddSiteVC.swift */,
|
||||
C4D9F24A280B69E100DCD39A /* AddProxyVC.swift */,
|
||||
);
|
||||
path = DomainList;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C47331A0247093AC009A0597 /* Menu */ = {
|
||||
@ -573,6 +751,7 @@
|
||||
children = (
|
||||
C40C7F1D2772136000DDDCDC /* PhpEnv.swift */,
|
||||
C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */,
|
||||
C4D936C827E3EB6100BD69FE /* PhpHelper.swift */,
|
||||
);
|
||||
path = "PHP Version";
|
||||
sourceTree = "<group>";
|
||||
@ -581,7 +760,9 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4AF9F792754499000D44ED0 /* Valet.swift */,
|
||||
C4E4404527C56F4700D225E1 /* ValetSite.swift */,
|
||||
C42F26722805B4B400938AC7 /* DomainListable.swift */,
|
||||
C4C0E8D927F887BD002D32A9 /* Proxies */,
|
||||
C4C0E8D827F887A5002D32A9 /* Sites */,
|
||||
);
|
||||
path = Valet;
|
||||
sourceTree = "<group>";
|
||||
@ -589,6 +770,7 @@
|
||||
C4AF9F6B275445D300D44ED0 /* Integrations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4C0E8DA27F887CC002D32A9 /* Nginx */,
|
||||
C4D89BC42783C98800A02B68 /* Composer */,
|
||||
C4AF9F6C275445D900D44ED0 /* Homebrew */,
|
||||
C4AF9F6A275445C900D44ED0 /* Valet */,
|
||||
@ -617,6 +799,8 @@
|
||||
C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */,
|
||||
C4EED88827A48778006D7272 /* InterAppHandler.swift */,
|
||||
C4D8016522B1584700C6DA1B /* Startup.swift */,
|
||||
C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */,
|
||||
C40FE736282ABA4F00A302C2 /* AppVersion.swift */,
|
||||
);
|
||||
path = App;
|
||||
sourceTree = "<group>";
|
||||
@ -633,12 +817,60 @@
|
||||
path = Common;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C4C0E8D827F887A5002D32A9 /* Sites */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4E4404527C56F4700D225E1 /* ValetSite.swift */,
|
||||
C41C02A827E61A65009F26CB /* ValetSite+Fake.swift */,
|
||||
C4C0E8E427F88B1F002D32A9 /* SiteScanner */,
|
||||
);
|
||||
path = Sites;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C4C0E8D927F887BD002D32A9 /* Proxies */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4205A7D27F4D21800191A39 /* ValetProxy.swift */,
|
||||
C4C0E8E927F88B80002D32A9 /* ValetProxy+Fake.swift */,
|
||||
C4C0E8E527F88B36002D32A9 /* ProxyScanner */,
|
||||
);
|
||||
path = Proxies;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C4C0E8DA27F887CC002D32A9 /* Nginx */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4D5CFC927E0F9CD00035329 /* NginxConfiguration.swift */,
|
||||
);
|
||||
path = Nginx;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C4C0E8E427F88B1F002D32A9 /* SiteScanner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C41C02A527E60D7A009F26CB /* SiteScanner.swift */,
|
||||
C4C0E8E127F88B13002D32A9 /* ValetSiteScanner.swift */,
|
||||
C4C0E8DE27F88AEB002D32A9 /* FakeSiteScanner.swift */,
|
||||
);
|
||||
path = SiteScanner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C4C0E8E527F88B36002D32A9 /* ProxyScanner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4C0E8E627F88B41002D32A9 /* ProxyScanner.swift */,
|
||||
C484437A2804BB560041A78A /* ValetProxyScanner.swift */,
|
||||
);
|
||||
path = ProxyScanner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C4C1019727C65A11001FACC2 /* Parsers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C4AF9F76275447F100D44ED0 /* ValetConfigParserTest.swift */,
|
||||
C4F780AD25D80B37000DBC97 /* ExtensionParserTest.swift */,
|
||||
C43A8A2325D9D20D00591B77 /* BrewJsonParserTest.swift */,
|
||||
C4AF9F76275447F100D44ED0 /* ValetConfigurationTest.swift */,
|
||||
C4F780AD25D80B37000DBC97 /* PhpExtensionTest.swift */,
|
||||
C43A8A2325D9D20D00591B77 /* HomebrewPackageTest.swift */,
|
||||
C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */,
|
||||
);
|
||||
path = Parsers;
|
||||
sourceTree = "<group>";
|
||||
@ -650,6 +882,8 @@
|
||||
C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */,
|
||||
C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */,
|
||||
C4AF9F7C275454A900D44ED0 /* ValetVersionExtractorTest.swift */,
|
||||
C40FE739282ABB2E00A302C2 /* AppVersionTest.swift */,
|
||||
C46E206F2829D27F00D909D6 /* AppUpdaterCheckTest.swift */,
|
||||
);
|
||||
path = Versions;
|
||||
sourceTree = "<group>";
|
||||
@ -760,6 +994,7 @@
|
||||
C41C1B2F22B0097F00E7CF16 /* Sources */,
|
||||
C41C1B3022B0097F00E7CF16 /* Frameworks */,
|
||||
C41C1B3122B0097F00E7CF16 /* Resources */,
|
||||
C4F5FBCB28216985001065C5 /* Run `swiftlint` */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -767,7 +1002,6 @@
|
||||
);
|
||||
name = "PHP Monitor";
|
||||
packageProductDependencies = (
|
||||
C4998F0526175E7200B2526E /* HotKey */,
|
||||
);
|
||||
productName = phpmon;
|
||||
productReference = C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */;
|
||||
@ -788,7 +1022,6 @@
|
||||
);
|
||||
name = "phpmon-tests";
|
||||
packageProductDependencies = (
|
||||
C4C1019527C659B7001FACC2 /* HotKey */,
|
||||
);
|
||||
productName = "phpmon-tests";
|
||||
productReference = C4F7807925D7F84B000DBC97 /* phpmon-tests.xctest */;
|
||||
@ -822,7 +1055,6 @@
|
||||
);
|
||||
mainGroup = C41C1B2A22B0097F00E7CF16;
|
||||
packageReferences = (
|
||||
C4998F0426175E7200B2526E /* XCRemoteSwiftPackageReference "HotKey" */,
|
||||
);
|
||||
productRefGroup = C41C1B3422B0097F00E7CF16 /* Products */;
|
||||
projectDirPath = "";
|
||||
@ -863,17 +1095,43 @@
|
||||
files = (
|
||||
54FCFD27276C883F004CE748 /* SelectPreferenceView.xib in Resources */,
|
||||
54FCFD2E276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */,
|
||||
C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */,
|
||||
C4F780A825D80AE8000DBC97 /* php.ini in Resources */,
|
||||
C4068CA527B0780A00544CD5 /* CheckboxPreferenceView.xib in Resources */,
|
||||
C43A8A2025D9D1D700591B77 /* brew.json in Resources */,
|
||||
C43A8A2025D9D1D700591B77 /* brew-formula.json in Resources */,
|
||||
C4AF9F72275445FF00D44ED0 /* valet-config.json in Resources */,
|
||||
C44C1992276E44CB0072762D /* ProgressWindow.storyboard in Resources */,
|
||||
C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */,
|
||||
C4F30B08278E195800755FCE /* brew-services.json in Resources */,
|
||||
54A18D40282A566E000A0D81 /* nginx-secure-proxy-custom-tld.test in Resources */,
|
||||
C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */,
|
||||
C459B4BD27F6093700E9B4B4 /* nginx-proxy.test in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
C4F5FBCB28216985001065C5 /* Run `swiftlint` */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run `swiftlint`";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
C41C1B2F22B0097F00E7CF16 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
@ -887,6 +1145,7 @@
|
||||
C4998F0A2617633900B2526E /* PrefsWC.swift in Sources */,
|
||||
C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */,
|
||||
C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */,
|
||||
C4C0E8EA27F88B80002D32A9 /* ValetProxy+Fake.swift in Sources */,
|
||||
5420395926135DC100FB00FA /* PrefsVC.swift in Sources */,
|
||||
C43603A0275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */,
|
||||
C4068CA727B07A1300544CD5 /* SelectPreferenceView.swift in Sources */,
|
||||
@ -894,22 +1153,32 @@
|
||||
C4E0F7ED27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */,
|
||||
C49E171F27A5736E00787921 /* PMServicesView.swift in Sources */,
|
||||
C4EE55AD27708B9E001DF387 /* PMStatsView.swift in Sources */,
|
||||
C4205A7E27F4D21800191A39 /* ValetProxy.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 */,
|
||||
C4D9F24B280B69E100DCD39A /* AddProxyVC.swift in Sources */,
|
||||
C41E871A2763D42300161EE0 /* DomainListVC+ContextMenu.swift in Sources */,
|
||||
C48D0CA325CC992000CC7490 /* StatsView.swift in Sources */,
|
||||
C40C7F2827721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */,
|
||||
C4EE55A927708B9E001DF387 /* PMHeaderView.swift in Sources */,
|
||||
C41C02A927E61A65009F26CB /* ValetSite+Fake.swift in Sources */,
|
||||
C4C0E8DF27F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */,
|
||||
C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */,
|
||||
C40FE737282ABA4F00A302C2 /* AppVersion.swift in Sources */,
|
||||
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */,
|
||||
C4B585442770FE3900DA4FBE /* Command.swift in Sources */,
|
||||
C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */,
|
||||
C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */,
|
||||
C4EE55AB27708B9E001DF387 /* Preview.swift in Sources */,
|
||||
C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */,
|
||||
C415D3B72770F294005EF286 /* Actions.swift in Sources */,
|
||||
C4AC51FC27E27F47008528CA /* DomainListKindCell.swift in Sources */,
|
||||
C44C198D276E3A1C0072762D /* ProgressWindow.swift in Sources */,
|
||||
54D9E0B827E4F51E003B9AD9 /* KeyCombo.swift in Sources */,
|
||||
C4C0E8E727F88B41002D32A9 /* ProxyScanner.swift in Sources */,
|
||||
C4C3ED4327834C5200AB15D8 /* CustomPrefs.swift in Sources */,
|
||||
54B48B5F275F66AE006D90C5 /* Application.swift in Sources */,
|
||||
C4B97B78275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */,
|
||||
@ -918,27 +1187,35 @@
|
||||
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */,
|
||||
C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */,
|
||||
C4F30B03278E16BA00755FCE /* HomebrewService.swift in Sources */,
|
||||
54D9E0B427E4F51E003B9AD9 /* Key.swift in Sources */,
|
||||
C4C0E8E227F88B13002D32A9 /* ValetSiteScanner.swift in Sources */,
|
||||
C42F26732805B4B400938AC7 /* DomainListable.swift in Sources */,
|
||||
5420395F2613607600FB00FA /* Preferences.swift in Sources */,
|
||||
C48D0C9325CC804200CC7490 /* XibLoadable.swift in Sources */,
|
||||
54FCFD2A276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */,
|
||||
54D9E0B227E4F51E003B9AD9 /* HotKeysController.swift in Sources */,
|
||||
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */,
|
||||
C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */,
|
||||
C41CA5ED2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */,
|
||||
C41CA5ED2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */,
|
||||
C46E206D28299B3800D909D6 /* AppUpdateChecker.swift in Sources */,
|
||||
C412E5FC25700D5300A1FB67 /* HomebrewPackage.swift in Sources */,
|
||||
C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */,
|
||||
C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */,
|
||||
C4C8E81B276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */,
|
||||
C417DC74277614690015E6EE /* Helpers.swift in Sources */,
|
||||
C415D3E82770F692005EF286 /* AppDelegate+InterApp.swift in Sources */,
|
||||
C484437B2804BB560041A78A /* ValetProxyScanner.swift in Sources */,
|
||||
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */,
|
||||
C42759672627662800093CAE /* NSMenuExtension.swift in Sources */,
|
||||
C464ADAF275A7A69003FCD53 /* SiteListVC.swift in Sources */,
|
||||
C464ADAF275A7A69003FCD53 /* DomainListVC.swift in Sources */,
|
||||
C44CCD4927AFF3B700CE40E5 /* MainMenu+Async.swift in Sources */,
|
||||
C4C1019B27C65C6F001FACC2 /* Process.swift in Sources */,
|
||||
C4EC1E73279DFCF40010F296 /* Events.swift in Sources */,
|
||||
C44067FB27E25FD70045BD4E /* DomainListTLSCell.swift in Sources */,
|
||||
C4927F0B27B2DFC200C55AFD /* Errors.swift in Sources */,
|
||||
C4B5853E2770FE3900DA4FBE /* Paths.swift in Sources */,
|
||||
C41C1B4B22B019FF00E7CF16 /* ActivePhpInstallation.swift in Sources */,
|
||||
C4FE011128084FC200D1DE6D /* SelectionVC.swift in Sources */,
|
||||
C44CCD4027AFE2FC00CE40E5 /* AlertableError.swift in Sources */,
|
||||
C4188989275FE8CB001EF227 /* Filesystem.swift in Sources */,
|
||||
C4B97B7B275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */,
|
||||
@ -947,17 +1224,24 @@
|
||||
C476FF9822B0DD830098105B /* Alert.swift in Sources */,
|
||||
C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */,
|
||||
C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */,
|
||||
C4D5CFCA27E0F9CD00035329 /* NginxConfiguration.swift in Sources */,
|
||||
C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */,
|
||||
C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */,
|
||||
C4080FFA27BD956700BF2C6B /* BetterAlertVC.swift in Sources */,
|
||||
C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */,
|
||||
54D9E0B627E4F51E003B9AD9 /* HotKey.swift in Sources */,
|
||||
C4D936C927E3EB6100BD69FE /* PhpHelper.swift in Sources */,
|
||||
C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */,
|
||||
C44067F927E2585E0045BD4E /* DomainListTypeCell.swift in Sources */,
|
||||
54D9E0BA27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */,
|
||||
C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */,
|
||||
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */,
|
||||
C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */,
|
||||
C42337A3281F19F000459A48 /* Xdebug.swift in Sources */,
|
||||
C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */,
|
||||
C464ADAC275A7A3F003FCD53 /* SiteListWC.swift in Sources */,
|
||||
C464ADB2275A87CA003FCD53 /* SiteListCell.swift in Sources */,
|
||||
C41C02A627E60D7A009F26CB /* SiteScanner.swift in Sources */,
|
||||
C464ADAC275A7A3F003FCD53 /* DomainListWC.swift in Sources */,
|
||||
C464ADB2275A87CA003FCD53 /* DomainListCellProtocol.swift in Sources */,
|
||||
C4EE188422D3386B00E126E5 /* Constants.swift in Sources */,
|
||||
C493084A279F331F009C240B /* AddSiteVC.swift in Sources */,
|
||||
C4DEB7D427A5D60B00834718 /* Stats.swift in Sources */,
|
||||
@ -968,60 +1252,80 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C449B4F427EE7FC800C47E8A /* DomainListKindCell.swift in Sources */,
|
||||
54EAC806262F212B0092D14E /* GlobalKeybindPreference.swift in Sources */,
|
||||
C4EE55AE27708B9E001DF387 /* PMStatsView.swift in Sources */,
|
||||
C41CA5EE2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */,
|
||||
C41CA5EE2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */,
|
||||
54D9E0B727E4F51E003B9AD9 /* HotKey.swift in Sources */,
|
||||
C4205A7F27F4D21800191A39 /* ValetProxy.swift in Sources */,
|
||||
C42F26742805B4B400938AC7 /* DomainListable.swift in Sources */,
|
||||
C4F780C425D80B75000DBC97 /* MainMenu.swift in Sources */,
|
||||
54FCFD2B276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */,
|
||||
C415D3B82770F294005EF286 /* Actions.swift in Sources */,
|
||||
54B48B60275F66AE006D90C5 /* Application.swift in Sources */,
|
||||
C4FE011228084FC200D1DE6D /* SelectionVC.swift in Sources */,
|
||||
C4F780C825D80B75000DBC97 /* DateExtension.swift in Sources */,
|
||||
C493084B279F331F009C240B /* AddSiteVC.swift in Sources */,
|
||||
C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */,
|
||||
C41C02AA27E61CA3009F26CB /* SiteScanner.swift in Sources */,
|
||||
C4080FFB27BD956700BF2C6B /* BetterAlertVC.swift in Sources */,
|
||||
C4F780CC25D80B75000DBC97 /* ActivePhpInstallation.swift in Sources */,
|
||||
54D9E0BB27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */,
|
||||
C4F780B125D80B4D000DBC97 /* PhpExtension.swift in Sources */,
|
||||
C4D5CFCB27E0F9CD00035329 /* NginxConfiguration.swift in Sources */,
|
||||
C4068CA827B07A1300544CD5 /* SelectPreferenceView.swift in Sources */,
|
||||
C4F780CE25D80B75000DBC97 /* LocalNotification.swift in Sources */,
|
||||
C40C7F2927721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */,
|
||||
C4C0E8E827F88B41002D32A9 /* ProxyScanner.swift in Sources */,
|
||||
C449B4F027EE7FB800C47E8A /* DomainListTLSCell.swift in Sources */,
|
||||
C4FBFC532616485F00CDB8E1 /* PhpVersionDetectionTest.swift in Sources */,
|
||||
C43A8A2425D9D20D00591B77 /* BrewJsonParserTest.swift in Sources */,
|
||||
C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */,
|
||||
C4F780CA25D80B75000DBC97 /* HomebrewPackage.swift in Sources */,
|
||||
C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */,
|
||||
C4F319C927B034A500AFF46F /* Stats.swift in Sources */,
|
||||
C4F30B04278E16BA00755FCE /* HomebrewService.swift in Sources */,
|
||||
54D9E0B527E4F51E003B9AD9 /* Key.swift in Sources */,
|
||||
C4AF9F7B2754499000D44ED0 /* Valet.swift in Sources */,
|
||||
C4C1019C27C65C6F001FACC2 /* Process.swift in Sources */,
|
||||
C4F780C025D80B6E000DBC97 /* Startup.swift in Sources */,
|
||||
C4C0E8E327F88B13002D32A9 /* ValetSiteScanner.swift in Sources */,
|
||||
C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */,
|
||||
C4B5635F276AB09000F12CCB /* VersionExtractor.swift in Sources */,
|
||||
C4BF90C127C57C220054E78C /* MainMenu+FixMyValet.swift in Sources */,
|
||||
C4C0E8EB27F88B80002D32A9 /* ValetProxy+Fake.swift in Sources */,
|
||||
C4F2E4382752F08D0020E974 /* HomebrewDiagnostics.swift in Sources */,
|
||||
C4F780AE25D80B37000DBC97 /* ExtensionParserTest.swift in Sources */,
|
||||
C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */,
|
||||
C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
|
||||
54D9E0B927E4F51E003B9AD9 /* KeyCombo.swift in Sources */,
|
||||
C4EED88A27A48778006D7272 /* InterAppHandler.swift in Sources */,
|
||||
C48D6C75279CD3E400F26D7E /* PhpVersionNumberTest.swift in Sources */,
|
||||
C43603A1275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */,
|
||||
C42759682627662800093CAE /* NSMenuExtension.swift in Sources */,
|
||||
C4D936CB27E3EE4A00BD69FE /* DomainListCellProtocol.swift in Sources */,
|
||||
C4B97B76275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */,
|
||||
C4F780CD25D80B75000DBC97 /* Alert.swift in Sources */,
|
||||
C481F79726164A78004FBCFF /* PrefsVC.swift in Sources */,
|
||||
C41E871B2763D42300161EE0 /* SiteListVC+ContextMenu.swift in Sources */,
|
||||
C41E871B2763D42300161EE0 /* DomainListVC+ContextMenu.swift in Sources */,
|
||||
C40C7F3127722E8D00DDDCDC /* Logger.swift in Sources */,
|
||||
C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */,
|
||||
C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */,
|
||||
C464ADB3275A87CA003FCD53 /* SiteListCell.swift in Sources */,
|
||||
C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */,
|
||||
C415D3E92770F692005EF286 /* AppDelegate+InterApp.swift in Sources */,
|
||||
C4AF9F78275447F100D44ED0 /* ValetConfigParserTest.swift in Sources */,
|
||||
C484437C2804BB560041A78A /* ValetProxyScanner.swift in Sources */,
|
||||
C4AF9F78275447F100D44ED0 /* ValetConfigurationTest.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 */,
|
||||
54D9E0B327E4F51E003B9AD9 /* HotKeysController.swift in Sources */,
|
||||
C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */,
|
||||
C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */,
|
||||
C46E20702829D27F00D909D6 /* AppUpdaterCheckTest.swift in Sources */,
|
||||
C4F7809C25D80344000DBC97 /* CommandTest.swift in Sources */,
|
||||
C44CCD4127AFE2FC00CE40E5 /* AlertableError.swift in Sources */,
|
||||
C4D936CA27E3EB6100BD69FE /* PhpHelper.swift in Sources */,
|
||||
C449B4F127EE7FC200C47E8A /* DomainListNameCell.swift in Sources */,
|
||||
C4F780BA25D80B62000DBC97 /* AppDelegate.swift in Sources */,
|
||||
54FCFD31276C8DA4004CE748 /* HotkeyPreferenceView.swift in Sources */,
|
||||
C4998F0B2617633900B2526E /* PrefsWC.swift in Sources */,
|
||||
@ -1031,9 +1335,13 @@
|
||||
C44C198E276E3A1C0072762D /* ProgressWindow.swift in Sources */,
|
||||
C415938027A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */,
|
||||
C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */,
|
||||
C449B4F227EE7FC400C47E8A /* DomainListPhpCell.swift in Sources */,
|
||||
C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */,
|
||||
C4F30B0B278E203C00755FCE /* MainMenu+Startup.swift in Sources */,
|
||||
C4F5FBCD28218CB8001065C5 /* Xdebug.swift in Sources */,
|
||||
C40B24F227A310770018C7D2 /* Events.swift in Sources */,
|
||||
C4F30B0A278E1A1A00755FCE /* ComposerJson.swift in Sources */,
|
||||
C4C0E8E027F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */,
|
||||
C4AF9F7D275454A900D44ED0 /* ValetVersionExtractorTest.swift in Sources */,
|
||||
C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */,
|
||||
C4B585452770FE3900DA4FBE /* Command.swift in Sources */,
|
||||
@ -1043,20 +1351,25 @@
|
||||
C4927F0C27B2DFC200C55AFD /* Errors.swift in Sources */,
|
||||
C4E4404727C56F4700D225E1 /* ValetSite.swift in Sources */,
|
||||
C44CCD4A27AFF3BC00CE40E5 /* MainMenu+Async.swift in Sources */,
|
||||
C449B4F327EE7FC600C47E8A /* DomainListTypeCell.swift in Sources */,
|
||||
C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */,
|
||||
C41C02AB27E61CB3009F26CB /* ValetSite+Fake.swift in Sources */,
|
||||
C4F780C925D80B75000DBC97 /* StringExtension.swift in Sources */,
|
||||
C4D9F24C280B69E100DCD39A /* AddProxyVC.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 */,
|
||||
C464ADAD275A7A3F003FCD53 /* DomainListWC.swift in Sources */,
|
||||
C40C7F1F2772136000DDDCDC /* PhpEnv.swift in Sources */,
|
||||
C4F780CB25D80B75000DBC97 /* StatsView.swift in Sources */,
|
||||
C464ADB0275A7A6A003FCD53 /* SiteListVC.swift in Sources */,
|
||||
C464ADB0275A7A6A003FCD53 /* DomainListVC.swift in Sources */,
|
||||
C43A8A1A25D9CD1000591B77 /* Utility.swift in Sources */,
|
||||
C418898A275FE8CB001EF227 /* Filesystem.swift in Sources */,
|
||||
C40FE73B282ABB2E00A302C2 /* AppVersionTest.swift in Sources */,
|
||||
C4F780C625D80B75000DBC97 /* XibLoadable.swift in Sources */,
|
||||
C4EE55AA27708B9E001DF387 /* PMHeaderView.swift in Sources */,
|
||||
C46E206E28299B3800D909D6 /* AppUpdateChecker.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1207,7 +1520,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 717;
|
||||
CURRENT_PROJECT_VERSION = 787;
|
||||
DEBUG = YES;
|
||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@ -1217,7 +1530,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 5.1.1;
|
||||
MARKETING_VERSION = 5.3.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -1233,7 +1546,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 717;
|
||||
CURRENT_PROJECT_VERSION = 787;
|
||||
DEBUG = NO;
|
||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@ -1243,7 +1556,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 5.1.1;
|
||||
MARKETING_VERSION = 5.3.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -1320,30 +1633,6 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
C4998F0426175E7200B2526E /* XCRemoteSwiftPackageReference "HotKey" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/soffes/HotKey";
|
||||
requirement = {
|
||||
kind = upToNextMinorVersion;
|
||||
minimumVersion = 0.1.3;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
C4998F0526175E7200B2526E /* HotKey */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = C4998F0426175E7200B2526E /* XCRemoteSwiftPackageReference "HotKey" */;
|
||||
productName = HotKey;
|
||||
};
|
||||
C4C1019527C659B7001FACC2 /* HotKey */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = C4998F0426175E7200B2526E /* XCRemoteSwiftPackageReference "HotKey" */;
|
||||
productName = HotKey;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = C41C1B2B22B0097F00E7CF16 /* Project object */;
|
||||
}
|
||||
|
@ -61,6 +61,19 @@
|
||||
ReferencedContainer = "container:PHP Monitor.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "--v"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "PHPMON_MARKETING_MODE"
|
||||
value = "YES"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
83
README.md
@ -1,17 +1,12 @@
|
||||
> If this software has been useful to you, I ask that you **please star the repository**, that way I know that the software is being used. Also, please consider leaving [a one-time donation](https://nicoverbruggen.be/sponsor) to support the project.
|
||||
> You can also send me [feedback](https://twitter.com/nicoverbruggen) if the app came in handy.<br>**Thank you!** ⭐️
|
||||
> If this software has been useful to you, I ask that you **please star the repository**, that way I know that the software is being used. Also, please consider leaving [a one-time donation](https://nicoverbruggen.be/sponsor) to support the project, as this is something I make in my free time. **Thank you!** ⭐️
|
||||
|
||||
<h1 align="center"><b>PHP Monitor</b> (phpmon)</h1>
|
||||
<p align="center"><img src="./docs/logo.png" alt="PHP Monitor Logo" width="500px" /></p>
|
||||
|
||||
<p align="center">
|
||||
<img src="./phpmon/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png" alt="phpmon icon" width="128px" />
|
||||
</p>
|
||||
**PHP Monitor** (or *phpmon*) is a lightweight macOS utility app that runs on your Mac and displays the active PHP version in your status bar. It's tightly integrated with [Laravel Valet](https://github.com/laravel/valet), so <u>you need to have it set up before you can use this app</u> (consult the FAQ below with info about how to set up your environment).
|
||||
|
||||
**PHP Monitor** (or *phpmon*) is a lightweight macOS utility app that runs on your Mac and displays the active PHP version in your status bar. It's tightly integrated with [Laravel Valet](https://github.com/laravel/valet), so <u>you need to have it set up before you can use this</u>.
|
||||
<img src="./docs/screenshot.jpg" width="1085px" alt="phpmon screenshot (menu bar app)"/>
|
||||
|
||||
<img src="./docs/screenshot50.jpg" width="1085px" alt="phpmon screenshot (menu bar app)"/>
|
||||
|
||||
<small><i>Screenshot: Showing the key functionality of PHP Monitor. You can also add new domains as links, manage various services, and perform First Aid to fix all kinds of common PHP link issues.</i></small>
|
||||
<small><i>Screenshot: Showing the key functionality of PHP Monitor.</i></small>
|
||||
|
||||
It's super convenient to switch between different versions of PHP. You'll even get notifications (only if you choose to opt-in, of course)!
|
||||
|
||||
@ -19,16 +14,19 @@ It's super convenient to switch between different versions of PHP. You'll even g
|
||||
|
||||
PHP Monitor also gives you quick access to various useful functionality (like accessing configuration files, restarting services, and more).
|
||||
|
||||
You can also add new domains as links, isolate sites, manage various services, and perform First Aid to fix all kinds of common PHP link issues.
|
||||
|
||||
## 🖥 System requirements
|
||||
|
||||
PHP Monitor is a universal application that runs natively on Apple Silicon **and** Intel-based Macs.
|
||||
|
||||
* Your user account can administer your computer (required for some functionality, e.g. certificate generation)
|
||||
* macOS 11 Big Sur or higher (supports macOS 12 Monterey)
|
||||
* Homebrew is installed in `/usr/local/homebrew` or `/opt/homebrew`
|
||||
* The brew formula `php` has to be installed (which version is detected)
|
||||
* Laravel Valet 2.16.2 or higher (older versions might be compatible but are not supported)
|
||||
* Homebrew `php` formula is installed
|
||||
* Laravel Valet 2.16 or newer (supports Valet 3)
|
||||
|
||||
_You may need to update your Valet installation to keep everything working if a major version update of PHP has been released. You can do this by running `composer global update && valet install`._
|
||||
_You may need to update your Valet installation to keep everything working if a major version update of PHP has been released. You can do this by running `composer global update && valet install`. Some features are not supported when running Valet 2._
|
||||
|
||||
## 🚀 How to install
|
||||
|
||||
@ -79,7 +77,7 @@ If you're still having issues, here's a few common questions & answers, as well
|
||||
<summary><strong>Which versions of PHP are supported?</strong></summary>
|
||||
|
||||
<ul>
|
||||
<li>PHP 5.6</li>
|
||||
<li>PHP 5.6 (only if you are running Valet 2)</li>
|
||||
<li>PHP 7.0</li>
|
||||
<li>PHP 7.1</li>
|
||||
<li>PHP 7.2</li>
|
||||
@ -90,7 +88,7 @@ If you're still having issues, here's a few common questions & answers, as well
|
||||
<li>PHP 8.2 (experimental)</li>
|
||||
</ul>
|
||||
|
||||
For more details, consult the [constants file](https://github.com/nicoverbruggen/phpmon/blob/main/phpmon/Constants.swift#L16) file to see which versions are supported.
|
||||
For more details, consult the [constants file](https://github.com/nicoverbruggen/phpmon/blob/main/phpmon/Common/Core/Constants.swift#L16) file to see which versions are supported.
|
||||
|
||||
</details>
|
||||
|
||||
@ -151,6 +149,38 @@ This should install `dnsmasq` and set up Valet. Great, almost there!
|
||||
Finally, run PHP Monitor. Since the app is notarized and signed with a developer ID, it should work.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>How frequently does PHP Monitor check for updates?</strong></summary>
|
||||
|
||||
PHP Monitor will check if an update is available every time you start the app.
|
||||
|
||||
You can disable this behaviour by going to Preferences (via the PHP Monitor icon in the menu bar) and unchecking "Automatically check for updates". You can always check for updates manually.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>I have PHP Monitor installed, and it works. I want to upgrade my PHP installations to the latest version, what's the best way to do this?</strong></summary>
|
||||
|
||||
It's easy to make a mistake here, and end up with an unlinked version of PHP or have versions missing from PHP Monitor.
|
||||
|
||||
Here's what I usually do:
|
||||
|
||||
* Open PHP Monitor and select **First Aid & Services** > **Restore Homebrew Permissions**.
|
||||
* Close PHP Monitor after the pop-up tells you the permissions were restored.
|
||||
* Run `brew update-reset`
|
||||
* Run `brew upgrade`
|
||||
|
||||
If after this, any PHP versions are missing in PHP Monitor, please run the following for the versions that are missing:
|
||||
|
||||
* Run `brew uninstall php@x.x` (where `x.x` is the version)
|
||||
* Run `brew cleanup` (if you get any permission issues you may need to manually clean up the folder)
|
||||
* Run `brew install php@x.x` (where `x.x` is the version)
|
||||
|
||||
You may still need to run `brew link php` after upgrading, too.
|
||||
|
||||
That's it. Now start up PHP Monitor again and you should be golden!
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>PHP Monitor tells me `php` is not installed...</strong></summary>
|
||||
|
||||
@ -204,6 +234,12 @@ Usually this is a duplicate extension declaration causing issues, or an extensio
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>The option to isolate a site is disabled! What's going on?</strong></summary>
|
||||
|
||||
Make sure you have at least **Valet 3.0** installed, since support for isolation was added in this version of Valet. (Please note that this version of Valet drops support for PHP 5.6.)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>One of the limits (memory limit, max POST size, max upload size) shows an exclamation mark!</strong></summary>
|
||||
|
||||
@ -251,9 +287,13 @@ PHP Monitor is a universal app and supports both architectures, so [find out her
|
||||
<details>
|
||||
<summary><strong>Why is the app doing network requests?</strong></summary>
|
||||
|
||||
It's Homebrew. I can't prevent `brew` from doing things via the network when I invoke it.
|
||||
The app will automatically check for updates, which is the most likely culprit.
|
||||
|
||||
PHP Monitor itself doesn't do any network requests. Feel free to check the source code or intercept the traffic, if you don't believe me.
|
||||
This happens at launch (unless disabled), and the app directly checks the Caskfile hosted on GitHub. This data is not, and will not be used for analytics (and, as far as I can tell, cannot).
|
||||
|
||||
I also can't prevent `brew` from doing things via the network when PHP Monitor uses the binary.
|
||||
|
||||
The app includes an Internet Access Policy file, so if you're using something like Little Snitch there should be a description why these calls occur.
|
||||
|
||||
</details>
|
||||
|
||||
@ -366,13 +406,14 @@ Donations really help with the Apple Developer Program cost, and keep me motivat
|
||||
|
||||
## 😎 Acknowledgements
|
||||
|
||||
While I did make this application during my own free time, I have been lucky enough to do various experiments during work hours at [DIVE](https://dive.be). I'd also like to shout out the following folks:
|
||||
While I did make this application during my own free time, PHP Monitor started out from various learning experiments during work hours at my employer, DIVE. I'd also like to shout out the following folks:
|
||||
|
||||
* My colleagues at [DIVE](https://dive.be)
|
||||
* The [Homebrew](https://brew.sh/) team & [Valet maintainers](https://github.com/laravel/valet/graphs/contributors)
|
||||
* Various folks who [reached](https://twitter.com/stauffermatt) [out](https://twitter.com/marcelpociot) when PHP Monitor was still very much a small app with a handful of stars or so
|
||||
* My [GitHub Sponsors](https://github.com/sponsors/nicoverbruggen) and those who have donated
|
||||
* Everyone who has left feedback and reported bugs (appreciate it!)
|
||||
* Everyone in the Laravel community who shared the app (thanks!)
|
||||
* Everyone who left feedback via issues & who donated to keep the project up and running
|
||||
|
||||
Thank you very much for your contributions, kind words and support.
|
||||
|
||||
@ -388,7 +429,9 @@ In order to save power, this only happens once every 60 seconds.
|
||||
|
||||
This utility will detect which PHP versions you have installed via Homebrew, and then allows you to switch between them.
|
||||
|
||||
The switcher will disable all PHP-FPM services not belonging to the version you wish to use, and link the desired version of PHP. Then, it'll restart your desired PHP version's FPM process. This all happens in parallel, so this should be much faster than Valet’s switcher.
|
||||
The switcher will disable all PHP-FPM services not belonging to the version you wish to use, and link the desired version of PHP. Then, it'll restart your desired PHP version's FPM process. This all happens in parallel, so this should be a bit faster than Valet’s switcher.
|
||||
|
||||
If you're using Valet 3, versions of PHP-FPM required to keep isolated sites up and running will also be started or stopped as needed.
|
||||
|
||||
### Config change detection
|
||||
|
||||
|
@ -4,9 +4,11 @@
|
||||
|
||||
Generally speaking, only the latest version of **PHP Monitor** is supported, except during transition periods (for example, when particular system requirements go up):
|
||||
|
||||
| Version | Apple Silicon | Supported | Supported macOS | Deployment Target | Detected PHP Versions | Minimum Required Valet Version |
|
||||
| Version | Apple Silicon | Supported | Supported macOS | Deployment Target | Detected PHP Versions | Recommended Valet Version |
|
||||
| ------- | ------------- | ------------------ | ----- | ----- | ----- | ----
|
||||
| 5 | ✅ Universal binary | ✅ Yes | Big Sur (11.0) and Monterey (12.0) | macOS 11+ | PHP 5.6—PHP 8.2 | 2.16.2 |
|
||||
| 5.x | ✅ Universal binary | ✅ Yes | Big Sur (11.0) and Monterey (12.0) | macOS 11+ | PHP 5.6—PHP 8.2 (*) | 3.0 (2.16.2 minimum) |
|
||||
|
||||
_(*) Support for PHP 5.6 is only included if you are using Valet 2.x, since support for PHP 5.6 was dropped in Valet 3.0._
|
||||
|
||||
## Legacy versions
|
||||
|
||||
|
BIN
docs/logo.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
docs/screenshot.jpg
Normal file
After Width: | Height: | Size: 345 KiB |
Before Width: | Height: | Size: 370 KiB |
@ -3,7 +3,7 @@
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 13/02/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
@ -3,18 +3,18 @@
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 14/02/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class BrewJsonParserTest: XCTestCase {
|
||||
class HomebrewPackageTest: XCTestCase {
|
||||
|
||||
// - MARK: SYNTHETIC TESTS
|
||||
|
||||
static var jsonBrewFile: URL {
|
||||
return Bundle(for: Self.self)
|
||||
.url(forResource: "brew", withExtension: "json")!
|
||||
.url(forResource: "brew-formula", withExtension: "json")!
|
||||
}
|
||||
|
||||
func testCanLoadExtensionJson() throws {
|
||||
@ -64,9 +64,9 @@ class BrewJsonParserTest: XCTestCase {
|
||||
return ["php", "nginx", "dnsmasq"].contains(service.name)
|
||||
})
|
||||
|
||||
XCTAssertTrue(services.contains(where: {$0.name == "php"} ))
|
||||
XCTAssertTrue(services.contains(where: {$0.name == "nginx"} ))
|
||||
XCTAssertTrue(services.contains(where: {$0.name == "dnsmasq"} ))
|
||||
XCTAssertTrue(services.contains(where: {$0.name == "php"}))
|
||||
XCTAssertTrue(services.contains(where: {$0.name == "nginx"}))
|
||||
XCTAssertTrue(services.contains(where: {$0.name == "dnsmasq"}))
|
||||
XCTAssertEqual(services.count, 3)
|
||||
}
|
||||
|
81
phpmon-tests/Parsers/NginxConfigurationTest.swift
Normal file
@ -0,0 +1,81 @@
|
||||
//
|
||||
// NginxConfigurationTest.swift
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 29/11/2021.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class NginxConfigurationTest: XCTestCase {
|
||||
|
||||
// MARK: - Test Files
|
||||
|
||||
static var regularUrl: URL {
|
||||
return Bundle(for: Self.self).url(forResource: "nginx-site", withExtension: "test")!
|
||||
}
|
||||
|
||||
static var isolatedUrl: URL {
|
||||
return Bundle(for: Self.self).url(forResource: "nginx-site-isolated", withExtension: "test")!
|
||||
}
|
||||
|
||||
static var proxyUrl: URL {
|
||||
return Bundle(for: Self.self).url(forResource: "nginx-proxy", withExtension: "test")!
|
||||
}
|
||||
|
||||
static var secureProxyUrl: URL {
|
||||
return Bundle(for: Self.self).url(forResource: "nginx-secure-proxy", withExtension: "test")!
|
||||
}
|
||||
|
||||
static var customTldProxyUrl: URL {
|
||||
return Bundle(for: Self.self).url(forResource: "nginx-secure-proxy-custom-tld", withExtension: "test")!
|
||||
}
|
||||
|
||||
// MARK: - Tests
|
||||
|
||||
func testCanDetermineSiteNameAndTld() throws {
|
||||
XCTAssertEqual(
|
||||
"nginx-site",
|
||||
NginxConfiguration.from(filePath: NginxConfigurationTest.regularUrl.path)?.domain
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"test",
|
||||
NginxConfiguration.from(filePath: NginxConfigurationTest.regularUrl.path)?.tld
|
||||
)
|
||||
}
|
||||
|
||||
func testCanDetermineIsolation() throws {
|
||||
XCTAssertNil(
|
||||
NginxConfiguration.from(filePath: NginxConfigurationTest.regularUrl.path)?.isolatedVersion
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"8.1",
|
||||
NginxConfiguration.from(filePath: NginxConfigurationTest.isolatedUrl.path)?.isolatedVersion
|
||||
)
|
||||
}
|
||||
|
||||
func testCanDetermineProxy() throws {
|
||||
let proxied = NginxConfiguration.from(filePath: NginxConfigurationTest.proxyUrl.path)!
|
||||
XCTAssertTrue(proxied.contents.contains("# valet stub: proxy.valet.conf"))
|
||||
XCTAssertEqual("http://127.0.0.1:90", proxied.proxy)
|
||||
|
||||
let normal = NginxConfiguration.from(filePath: NginxConfigurationTest.regularUrl.path)!
|
||||
XCTAssertFalse(normal.contents.contains("# valet stub: proxy.valet.conf"))
|
||||
XCTAssertEqual(nil, normal.proxy)
|
||||
}
|
||||
|
||||
func testCanDetermineSecuredProxy() throws {
|
||||
let proxied = NginxConfiguration.from(filePath: NginxConfigurationTest.secureProxyUrl.path)!
|
||||
XCTAssertTrue(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
|
||||
XCTAssertEqual("http://127.0.0.1:90", proxied.proxy)
|
||||
}
|
||||
|
||||
func testCanDetermineProxyWithCustomTld() throws {
|
||||
let proxied = NginxConfiguration.from(filePath: NginxConfigurationTest.customTldProxyUrl.path)!
|
||||
XCTAssertTrue(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
|
||||
XCTAssertEqual("http://localhost:8080", proxied.proxy)
|
||||
}
|
||||
|
||||
}
|
@ -3,12 +3,12 @@
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 13/02/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class ExtensionParserTest: XCTestCase {
|
||||
class PhpExtensionTest: XCTestCase {
|
||||
|
||||
static var phpIniFileUrl: URL {
|
||||
return Bundle(for: Self.self).url(forResource: "php", withExtension: "ini")!
|
||||
@ -69,4 +69,9 @@ class ExtensionParserTest: XCTestCase {
|
||||
XCTAssertEqual(PhpExtension.load(from: destination).first!.enabled, false)
|
||||
}
|
||||
|
||||
func testCanRetrieveXdebugMode() throws {
|
||||
let value = Command.execute(path: Paths.php, arguments: ["-r", "echo ini_get('xdebug.mode');"])
|
||||
XCTAssertEqual(value, "coverage")
|
||||
}
|
||||
|
||||
}
|
@ -3,12 +3,12 @@
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 29/11/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class ValetConfigParserTest: XCTestCase {
|
||||
class ValetConfigurationTest: XCTestCase {
|
||||
|
||||
static var jsonConfigFileUrl: URL {
|
||||
return Bundle(for: Self.self).url(
|
||||
@ -32,6 +32,7 @@ class ValetConfigParserTest: XCTestCase {
|
||||
"/Users/username/.config/valet/Sites",
|
||||
"/Users/username/Sites"
|
||||
])
|
||||
XCTAssertEqual(config.defaultSite, "/Users/username/default-site")
|
||||
XCTAssertEqual(config.loopback, "127.0.0.1")
|
||||
}
|
||||
|
81
phpmon-tests/Test Files/nginx/nginx-proxy.test
Normal file
@ -0,0 +1,81 @@
|
||||
# valet stub: proxy.valet.conf
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:80;
|
||||
#listen 127.0.0.1:80; # valet loopback
|
||||
server_name my-proxy.test www.my-proxy.test *.my-proxy.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 128M;
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/my-proxy.test-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:90;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Client-Verify SUCCESS;
|
||||
proxy_set_header X-Client-DN $ssl_client_s_dn;
|
||||
proxy_set_header X-SSL-Subject $ssl_client_s_dn;
|
||||
proxy_set_header X-SSL-Issuer $ssl_client_i_dn;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
proxy_read_timeout 1800;
|
||||
proxy_connect_timeout 1800;
|
||||
chunked_transfer_encoding on;
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:60;
|
||||
#listen 127.0.0.1:60; # valet loopback
|
||||
server_name my-proxy.test www.my-proxy.test *.my-proxy.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 128M;
|
||||
|
||||
add_header X-Robots-Tag 'noindex, nofollow, nosnippet, noarchive';
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/my-proxy.test-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:90;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
# valet stub: secure.proxy.valet.conf
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:80;
|
||||
#listen 127.0.0.1:80; # valet loopback
|
||||
server_name live.whatagraph.dev.com www.live.whatagraph.dev.com *.live.whatagraph.dev.com;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:443 ssl http2;
|
||||
#listen 127.0.0.1:443 ssl http2; # valet loopback
|
||||
server_name live.whatagraph.dev.com www.live.whatagraph.dev.com *.live.whatagraph.dev.com;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 128M;
|
||||
http2_push_preload on;
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
ssl_certificate "/Users/phpmon/.config/valet/Certificates/live.whatagraph.dev.com.crt";
|
||||
ssl_certificate_key "/Users/phpmon/.config/valet/Certificates/live.whatagraph.dev.com.key";
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/phpmon/.config/valet/Log/live.whatagraph.dev.com-error.log";
|
||||
|
||||
error_page 404 "/Users/phpmon/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Client-Verify SUCCESS;
|
||||
proxy_set_header X-Client-DN $ssl_client_s_dn;
|
||||
proxy_set_header X-SSL-Subject $ssl_client_s_dn;
|
||||
proxy_set_header X-SSL-Issuer $ssl_client_i_dn;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
proxy_read_timeout 1800;
|
||||
proxy_connect_timeout 1800;
|
||||
chunked_transfer_encoding on;
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
57
phpmon-tests/Test Files/nginx/nginx-secure-proxy.test
Normal file
@ -0,0 +1,57 @@
|
||||
# valet stub: secure.proxy.valet.conf
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:80;
|
||||
#listen 127.0.0.1:80; # valet loopback
|
||||
server_name my-proxy.test www.my-proxy.test *.my-proxy.test;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:443 ssl http2;
|
||||
#listen 127.0.0.1:443 ssl http2; # valet loopback
|
||||
server_name my-proxy.test www.my-proxy.test *.my-proxy.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 128M;
|
||||
http2_push_preload on;
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
ssl_certificate "/Users/nicoverbruggen/.config/valet/Certificates/my-proxy.test.crt";
|
||||
ssl_certificate_key "/Users/nicoverbruggen/.config/valet/Certificates/my-proxy.test.key";
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/my-proxy.test-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:90;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Client-Verify SUCCESS;
|
||||
proxy_set_header X-Client-DN $ssl_client_s_dn;
|
||||
proxy_set_header X-SSL-Subject $ssl_client_s_dn;
|
||||
proxy_set_header X-SSL-Issuer $ssl_client_i_dn;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
proxy_read_timeout 1800;
|
||||
proxy_connect_timeout 1800;
|
||||
chunked_transfer_encoding on;
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
94
phpmon-tests/Test Files/nginx/nginx-site-isolated.test
Normal file
@ -0,0 +1,94 @@
|
||||
server {
|
||||
listen 127.0.0.1:80;
|
||||
#listen 127.0.0.1:80; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:443 ssl http2;
|
||||
#listen 127.0.0.1:443 ssl http2; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 512M;
|
||||
http2_push_preload on;
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
ssl_certificate "/Users/nicoverbruggen/.config/valet/Certificates/nicoverbruggen.test.crt";
|
||||
ssl_certificate_key "/Users/nicoverbruggen/.config/valet/Certificates/nicoverbruggen.test.key";
|
||||
|
||||
location / {
|
||||
rewrite ^ "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php" last;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/nginx-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
# ISOLATED_PHP_VERSION=php@8.1
|
||||
fastcgi_pass "unix:/Users/nicoverbruggen/.config/valet/valet81.sock";
|
||||
fastcgi_index "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:60;
|
||||
#listen 127.0.0.1:60; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 128M;
|
||||
|
||||
add_header X-Robots-Tag 'noindex, nofollow, nosnippet, noarchive';
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
location / {
|
||||
rewrite ^ "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php" last;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/nginx-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass "unix:/Users/nicoverbruggen/.config/valet/valet.sock";
|
||||
fastcgi_index "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
93
phpmon-tests/Test Files/nginx/nginx-site.test
Normal file
@ -0,0 +1,93 @@
|
||||
server {
|
||||
listen 127.0.0.1:80;
|
||||
#listen 127.0.0.1:80; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:443 ssl http2;
|
||||
#listen 127.0.0.1:443 ssl http2; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 512M;
|
||||
http2_push_preload on;
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
ssl_certificate "/Users/nicoverbruggen/.config/valet/Certificates/nicoverbruggen.test.crt";
|
||||
ssl_certificate_key "/Users/nicoverbruggen/.config/valet/Certificates/nicoverbruggen.test.key";
|
||||
|
||||
location / {
|
||||
rewrite ^ "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php" last;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/nginx-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass "unix:/Users/nicoverbruggen/.config/valet/valet.sock";
|
||||
fastcgi_index "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:60;
|
||||
#listen 127.0.0.1:60; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 128M;
|
||||
|
||||
add_header X-Robots-Tag 'noindex, nofollow, nosnippet, noarchive';
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
location / {
|
||||
rewrite ^ "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php" last;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/nginx-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass "unix:/Users/nicoverbruggen/.config/valet/valet.sock";
|
||||
fastcgi_index "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
@ -4,5 +4,6 @@
|
||||
"/Users/username/.config/valet/Sites",
|
||||
"/Users/username/Sites"
|
||||
],
|
||||
"loopback": "127.0.0.1"
|
||||
"loopback": "127.0.0.1",
|
||||
"default": "/Users/username/default-site"
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 14/02/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
21
phpmon-tests/Versions/AppUpdaterCheckTest.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// AppUpdaterCheckTest.swift
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 10/05/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class AppUpdaterCheckTest: XCTestCase {
|
||||
|
||||
func testCanRetrieveVersionFromCask() {
|
||||
let caskVersion = AppUpdateChecker.retrieveVersionFromCask()
|
||||
|
||||
let version = VersionExtractor.from(caskVersion)
|
||||
|
||||
XCTAssertNotNil(version)
|
||||
}
|
||||
|
||||
}
|
62
phpmon-tests/Versions/AppVersionTest.swift
Normal file
@ -0,0 +1,62 @@
|
||||
//
|
||||
// AppVersionTest.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 10/05/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class AppVersionTest: XCTestCase {
|
||||
|
||||
func testCanRetrieveInternalAppVersion() {
|
||||
XCTAssertNotNil(AppVersion.fromCurrentVersion())
|
||||
}
|
||||
|
||||
func testCanParseNormalVersionString() {
|
||||
let version = AppVersion.from("1.0.0")
|
||||
|
||||
XCTAssertNotNil(version)
|
||||
XCTAssertEqual("1.0.0", version?.version)
|
||||
XCTAssertEqual(nil, version?.build)
|
||||
XCTAssertEqual(nil, version?.suffix)
|
||||
}
|
||||
|
||||
func testCanParseCaskVersionString() {
|
||||
let version = AppVersion.from("1.0.0_600")
|
||||
|
||||
XCTAssertNotNil(version)
|
||||
XCTAssertEqual("1.0.0", version?.version)
|
||||
XCTAssertEqual("600", version?.build)
|
||||
XCTAssertEqual(nil, version?.suffix)
|
||||
}
|
||||
|
||||
func testCanParseDevVersionStringWithoutBuildNumber() {
|
||||
let version = AppVersion.from("1.0.0-dev")
|
||||
|
||||
XCTAssertNotNil(version)
|
||||
XCTAssertEqual("1.0.0", version?.version)
|
||||
XCTAssertEqual(nil, version?.build)
|
||||
XCTAssertEqual("dev", version?.suffix)
|
||||
}
|
||||
|
||||
func testCanParseDevVersionStringWithBuildNumber() {
|
||||
let version = AppVersion.from("1.0.0-dev,870")
|
||||
|
||||
XCTAssertNotNil(version)
|
||||
XCTAssertEqual("1.0.0", version?.version)
|
||||
XCTAssertEqual("870", version?.build)
|
||||
XCTAssertEqual("dev", version?.suffix)
|
||||
}
|
||||
|
||||
func testCanParseUnderscoresAsBuildSeparatorToo() {
|
||||
let version = AppVersion.from("1.0.0-dev_870")
|
||||
|
||||
XCTAssertNotNil(version)
|
||||
XCTAssertEqual("1.0.0", version?.version)
|
||||
XCTAssertEqual("870", version?.build)
|
||||
XCTAssertEqual("dev", version?.suffix)
|
||||
}
|
||||
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 01/04/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@ -22,8 +22,8 @@ class PhpVersionDetectionTest: XCTestCase {
|
||||
"unrelatedphp@1.0", // should be omitted, invalid
|
||||
"php@5.6",
|
||||
"php@5.4" // should be omitted, not supported
|
||||
], checkBinaries: false)
|
||||
], checkBinaries: false, generateHelpers: false)
|
||||
|
||||
XCTAssertEqual(outcome, ["8.0", "7.0", "5.6"])
|
||||
XCTAssertEqual(outcome, ["8.0", "7.0"])
|
||||
}
|
||||
}
|
||||
|
@ -11,20 +11,24 @@ import XCTest
|
||||
class PhpVersionNumberTest: XCTestCase {
|
||||
|
||||
func testCanDeconstructPhpVersion() throws {
|
||||
XCTAssertEqual(
|
||||
try! PhpVersionNumber.parse("PHP 8.2.0-dev"),
|
||||
PhpVersionNumber(major: 8, minor: 2, patch: 0)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
try! PhpVersionNumber.parse("PHP 8.1.0RC5-dev"),
|
||||
PhpVersionNumber(major: 8, minor: 1, patch: 0)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumber.make(from: "8.0.11"),
|
||||
try! PhpVersionNumber.parse("8.0.11"),
|
||||
PhpVersionNumber(major: 8, minor: 0, patch: 11)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumber.make(from: "7.4.2"),
|
||||
try! PhpVersionNumber.parse("7.4.2"),
|
||||
PhpVersionNumber(major: 7, minor: 4, patch: 2)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumber.make(from: "7.4"),
|
||||
try! PhpVersionNumber.parse("7.4"),
|
||||
PhpVersionNumber(major: 7, minor: 4, patch: nil)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
|
@ -3,7 +3,7 @@
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 29/11/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@ -12,7 +12,7 @@ class ValetVersionExtractorTest: XCTestCase {
|
||||
|
||||
func testDetermineValetVersion() {
|
||||
let version = valet("--version", sudo: false)
|
||||
XCTAssert(version.contains("Laravel Valet 2."))
|
||||
XCTAssert(version.contains("Laravel Valet 2") || version.contains("Laravel Valet 3"))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 16/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
25
phpmon/Assets.xcassets/IconDefault.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Default.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Default@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
BIN
phpmon/Assets.xcassets/IconDefault.imageset/Default.png
vendored
Normal file
After Width: | Height: | Size: 861 B |
BIN
phpmon/Assets.xcassets/IconDefault.imageset/Default@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.2 KiB |
25
phpmon/Assets.xcassets/IconProxy.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Proxy.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Proxy@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
BIN
phpmon/Assets.xcassets/IconProxy.imageset/Proxy.png
vendored
Normal file
After Width: | Height: | Size: 935 B |
BIN
phpmon/Assets.xcassets/IconProxy.imageset/Proxy@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.4 KiB |
25
phpmon/Assets.xcassets/Isolated.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Isolated.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Isolated@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
BIN
phpmon/Assets.xcassets/Isolated.imageset/Isolated.png
vendored
Normal file
After Width: | Height: | Size: 690 B |
BIN
phpmon/Assets.xcassets/Isolated.imageset/Isolated@2x.png
vendored
Normal file
After Width: | Height: | Size: 827 B |
@ -2,7 +2,7 @@
|
||||
// Services.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -12,37 +12,32 @@ class Actions {
|
||||
|
||||
// MARK: - Services
|
||||
|
||||
public static func restartPhpFpm()
|
||||
{
|
||||
public static func restartPhpFpm() {
|
||||
brew("services restart \(PhpEnv.phpInstall.formula)", sudo: true)
|
||||
}
|
||||
|
||||
public static func restartNginx()
|
||||
{
|
||||
public static func restartNginx() {
|
||||
brew("services restart nginx", sudo: true)
|
||||
}
|
||||
|
||||
public static func restartDnsMasq()
|
||||
{
|
||||
public static func restartDnsMasq() {
|
||||
brew("services restart dnsmasq", sudo: true)
|
||||
}
|
||||
|
||||
public static func stopAllServices()
|
||||
{
|
||||
public static func stopAllServices() {
|
||||
brew("services stop \(PhpEnv.phpInstall.formula)", sudo: true)
|
||||
brew("services stop nginx", sudo: true)
|
||||
brew("services stop dnsmasq", sudo: true)
|
||||
}
|
||||
|
||||
public static func fixHomebrewPermissions() throws
|
||||
{
|
||||
public static func fixHomebrewPermissions() throws {
|
||||
var servicesCommands = [
|
||||
"\(Paths.brew) services stop nginx",
|
||||
"\(Paths.brew) services stop dnsmasq",
|
||||
"\(Paths.brew) services stop dnsmasq"
|
||||
]
|
||||
var cellarCommands = [
|
||||
"chown -R \(Paths.whoami):staff \(Paths.cellarPath)/nginx",
|
||||
"chown -R \(Paths.whoami):staff \(Paths.cellarPath)/dnsmasq"
|
||||
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/nginx",
|
||||
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/dnsmasq"
|
||||
]
|
||||
|
||||
PhpEnv.shared.availablePhpVersions.forEach { version in
|
||||
@ -50,7 +45,7 @@ class Actions {
|
||||
? "php"
|
||||
: "php@\(version)"
|
||||
servicesCommands.append("\(Paths.brew) services stop \(formula)")
|
||||
cellarCommands.append("chown -R \(Paths.whoami):staff \(Paths.cellarPath)/\(formula)")
|
||||
cellarCommands.append("chown -R \(Paths.whoami):admin \(Paths.cellarPath)/\(formula)")
|
||||
}
|
||||
|
||||
let script =
|
||||
@ -64,34 +59,30 @@ class Actions {
|
||||
|
||||
let eventResult: NSAppleEventDescriptor? = appleScript?.executeAndReturnError(nil)
|
||||
|
||||
if (eventResult == nil) {
|
||||
if eventResult == nil {
|
||||
throw HomebrewPermissionError(kind: .applescriptNilError)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Finding Config Files
|
||||
|
||||
public static func openGenericPhpConfigFolder()
|
||||
{
|
||||
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php")];
|
||||
public static func openGenericPhpConfigFolder() {
|
||||
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php")]
|
||||
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
|
||||
}
|
||||
|
||||
public static func openGlobalComposerFolder()
|
||||
{
|
||||
public static func openGlobalComposerFolder() {
|
||||
let file = FileManager.default.homeDirectoryForCurrentUser
|
||||
.appendingPathComponent(".composer/composer.json")
|
||||
NSWorkspace.shared.activateFileViewerSelecting([file] as [URL])
|
||||
}
|
||||
|
||||
public static func openPhpConfigFolder(version: String)
|
||||
{
|
||||
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php/\(version)/php.ini")];
|
||||
public static func openPhpConfigFolder(version: String) {
|
||||
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php/\(version)/php.ini")]
|
||||
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
|
||||
}
|
||||
|
||||
public static func openValetConfigFolder()
|
||||
{
|
||||
public static func openValetConfigFolder() {
|
||||
let file = FileManager.default.homeDirectoryForCurrentUser
|
||||
.appendingPathComponent(".config/valet")
|
||||
NSWorkspace.shared.activateFileViewerSelecting([file] as [URL])
|
||||
@ -99,8 +90,7 @@ class Actions {
|
||||
|
||||
// MARK: - Other Actions
|
||||
|
||||
public static func createTempPhpInfoFile() -> URL
|
||||
{
|
||||
public static func createTempPhpInfoFile() -> URL {
|
||||
// Write a file called `phpmon_phpinfo.php` to /tmp
|
||||
try! "<?php phpinfo();".write(toFile: "/tmp/phpmon_phpinfo.php", atomically: true, encoding: .utf8)
|
||||
|
||||
@ -124,25 +114,12 @@ class Actions {
|
||||
If this does not solve the issue, the user may need to install additional
|
||||
extensions and/or run `composer global update`.
|
||||
*/
|
||||
public static func fixMyValet()
|
||||
{
|
||||
brew("services restart dnsmasq", sudo: true)
|
||||
|
||||
PhpEnv.shared.detectPhpVersions().forEach { (version) in
|
||||
let formula = (version == PhpEnv.brewPhpVersion) ? "php" : "php@\(version)"
|
||||
brew("unlink php@\(version)")
|
||||
brew("services stop \(formula)")
|
||||
brew("services stop \(formula)", sudo: true)
|
||||
}
|
||||
|
||||
brew("services stop dnsmasq")
|
||||
brew("services stop php")
|
||||
brew("services stop nginx")
|
||||
|
||||
brew("link php --overwrite --force")
|
||||
|
||||
brew("services restart dnsmasq", sudo: true)
|
||||
brew("services restart php", sudo: true)
|
||||
brew("services restart nginx", sudo: true)
|
||||
public static func fixMyValet(completed: @escaping () -> Void) {
|
||||
InternalSwitcher().performSwitch(to: PhpEnv.brewPhpVersion, completion: {
|
||||
brew("services restart dnsmasq", sudo: true)
|
||||
brew("services restart php", sudo: true)
|
||||
brew("services restart nginx", sudo: true)
|
||||
completed()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Command.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
@ -28,7 +28,7 @@ public class Command {
|
||||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
let output: String = String.init(data: data, encoding: String.Encoding.utf8)!
|
||||
|
||||
if (trimNewlines) {
|
||||
if trimNewlines {
|
||||
return output.components(separatedBy: .newlines)
|
||||
.filter({ !$0.isEmpty })
|
||||
.joined(separator: "\n")
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Constants.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
@ -34,7 +34,7 @@ struct Constants {
|
||||
// STABLE RELEASES
|
||||
// ====================
|
||||
// Versions of PHP that are stable and are supported.
|
||||
"5.6",
|
||||
"5.6", // only supported when Valet 2.x is active
|
||||
"7.0",
|
||||
"7.1",
|
||||
"7.2",
|
||||
@ -56,13 +56,27 @@ struct Constants {
|
||||
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"
|
||||
)!
|
||||
|
||||
static let GitHubReleases = URL(
|
||||
string: "https://github.com/nicoverbruggen/phpmon/releases"
|
||||
)!
|
||||
|
||||
static let StableBuildCaskFile = URL(
|
||||
string: "https://raw.githubusercontent.com/nicoverbruggen/homebrew-cask/master/Casks/phpmon.rb"
|
||||
)!
|
||||
|
||||
static let DevBuildCaskFile = URL(
|
||||
string: "https://raw.githubusercontent.com/nicoverbruggen/homebrew-cask/master/Casks/phpmon-dev.rb"
|
||||
)!
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 24/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
// MARK: Common Shell Commands
|
||||
@ -11,24 +11,21 @@
|
||||
/**
|
||||
Runs a `valet` command. Defaults to running as superuser.
|
||||
*/
|
||||
func valet(_ command: String, sudo: Bool = true) -> String
|
||||
{
|
||||
func valet(_ command: String, sudo: Bool = true) -> String {
|
||||
return Shell.pipe("\(sudo ? "sudo " : "")" + "\(Paths.valet) \(command)", requiresPath: true)
|
||||
}
|
||||
|
||||
/**
|
||||
Runs a `brew` command. Can run as superuser.
|
||||
*/
|
||||
func brew(_ command: String, sudo: Bool = false)
|
||||
{
|
||||
func brew(_ command: String, sudo: Bool = false) {
|
||||
Shell.run("\(sudo ? "sudo " : "")" + "\(Paths.brew) \(command)")
|
||||
}
|
||||
|
||||
/**
|
||||
Runs `sed` in order to replace all occurrences of a string in a specific file with another.
|
||||
*/
|
||||
func sed(file: String, original: String, replacement: String)
|
||||
{
|
||||
func sed(file: String, original: String, replacement: String) {
|
||||
// Escape slashes (or `sed` won't work)
|
||||
let e_original = original.replacingOccurrences(of: "/", with: "\\/")
|
||||
let e_replacement = replacement.replacingOccurrences(of: "/", with: "\\/")
|
||||
@ -45,8 +42,7 @@ func sed(file: String, original: String, replacement: String)
|
||||
/**
|
||||
Uses `grep` to determine whether a particular query string can be found in a particular file.
|
||||
*/
|
||||
func grepContains(file: String, query: String) -> Bool
|
||||
{
|
||||
func grepContains(file: String, query: String) -> Bool {
|
||||
return Shell.pipe("""
|
||||
grep -q '\(query)' \(file); [ $? -eq 0 ] && echo "YES" || echo "NO"
|
||||
""")
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 21/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Paths.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -49,7 +49,7 @@ public class Paths {
|
||||
// - MARK: Detected Binaries
|
||||
|
||||
/** The path to the Composer binary. Can be in multiple locations, so is detected instead. */
|
||||
public static var composer: String? = nil
|
||||
public static var composer: String?
|
||||
|
||||
// - MARK: Paths
|
||||
|
||||
|
@ -35,8 +35,11 @@ extension Process {
|
||||
forName: NSNotification.Name.NSFileHandleDataAvailable,
|
||||
object: pipe.fileHandleForReading,
|
||||
queue: nil
|
||||
) { notification in
|
||||
if let outputString = String(data: pipe.fileHandleForReading.availableData, encoding: String.Encoding.utf8) {
|
||||
) { _ in
|
||||
if let outputString = String(
|
||||
data: pipe.fileHandleForReading.availableData,
|
||||
encoding: String.Encoding.utf8
|
||||
) {
|
||||
callback(outputString)
|
||||
}
|
||||
pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Shell.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
@ -91,7 +91,7 @@ public class Shell {
|
||||
task.launch()
|
||||
task.waitUntilExit()
|
||||
|
||||
return Shell.Output(
|
||||
let output = Shell.Output(
|
||||
standardOutput: String(
|
||||
data: outputPipe.fileHandleForReading.readDataToEndOfFile(),
|
||||
encoding: .utf8
|
||||
@ -102,6 +102,12 @@ public class Shell {
|
||||
)!,
|
||||
task: task
|
||||
)
|
||||
|
||||
if CommandLine.arguments.contains("--v") {
|
||||
log(task: task, output: output)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,6 +125,23 @@ public class Shell {
|
||||
return task
|
||||
}
|
||||
|
||||
/**
|
||||
Verbose logging for PHP Monitor's synchronous shell output.
|
||||
*/
|
||||
private func log(task: Process, output: Output) {
|
||||
Log.info("")
|
||||
Log.info("==== COMMAND ====")
|
||||
Log.info("")
|
||||
Log.info("\(self.shell) \(task.arguments?.joined(separator: " ") ?? "")")
|
||||
Log.info("")
|
||||
Log.info("==== OUTPUT ====")
|
||||
Log.info("")
|
||||
dump(output)
|
||||
Log.info("")
|
||||
Log.info("==== END OUTPUT ====")
|
||||
Log.info("")
|
||||
}
|
||||
|
||||
public class Output {
|
||||
public let standardOutput: String
|
||||
public let errorOutput: String
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Date.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 14/04/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
@ -14,25 +14,25 @@ extension NSWindow {
|
||||
/**
|
||||
Shakes a window. Inspired by: http://blog.ericd.net/2016/09/30/shaking-a-macos-window/
|
||||
*/
|
||||
func shake(){
|
||||
func shake() {
|
||||
let numberOfShakes = 3, durationOfShake = 0.2, vigourOfShake: CGFloat = 0.03
|
||||
|
||||
let frame: CGRect = self.frame
|
||||
let shakeAnimation :CAKeyframeAnimation = CAKeyframeAnimation()
|
||||
let shakeAnimation: CAKeyframeAnimation = CAKeyframeAnimation()
|
||||
|
||||
let shakePath = CGMutablePath()
|
||||
shakePath.move( to: CGPoint(x:NSMinX(frame), y:NSMinY(frame)))
|
||||
shakePath.move( to: CGPoint(x: frame.minX, y: frame.minY))
|
||||
|
||||
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.addLine(to: CGPoint(x: frame.minX - frame.size.width * vigourOfShake, y: frame.minY))
|
||||
shakePath.addLine(to: CGPoint(x: frame.minX + frame.size.width * vigourOfShake, y: frame.minY))
|
||||
}
|
||||
|
||||
shakePath.closeSubpath()
|
||||
shakeAnimation.path = shakePath
|
||||
shakeAnimation.duration = durationOfShake
|
||||
|
||||
self.animations = ["frameOrigin":shakeAnimation]
|
||||
self.animations = ["frameOrigin": shakeAnimation]
|
||||
self.animator().setFrameOrigin(self.frame.origin)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// StringExtension.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
import Foundation
|
||||
|
||||
@ -17,7 +17,7 @@ extension String {
|
||||
}
|
||||
|
||||
func countInstances(of stringToFind: String) -> Int {
|
||||
if (stringToFind.isEmpty) {
|
||||
if stringToFind.isEmpty {
|
||||
return 0
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 04/02/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -26,10 +26,10 @@ extension XibLoadable where Self: NSView {
|
||||
|
||||
static func createFromXib(in bundle: Bundle = Bundle.main) -> Self? {
|
||||
guard let xibName = xibName else { return nil }
|
||||
var topLevelArray: NSArray? = nil
|
||||
var topLevelArray: NSArray?
|
||||
bundle.loadNibNamed(NSNib.Name(xibName), owner: self, topLevelObjects: &topLevelArray)
|
||||
guard let results = topLevelArray else { return nil }
|
||||
let views = Array<Any>(results).filter { $0 is Self }
|
||||
let views = [Any](results).filter { $0 is Self }
|
||||
return views.last as? Self
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Alert.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
@ -27,7 +27,7 @@ class Alert {
|
||||
alert.messageText = messageText
|
||||
alert.informativeText = informativeText
|
||||
alert.addButton(withTitle: buttonTitle)
|
||||
if (!secondButtonTitle.isEmpty) {
|
||||
if !secondButtonTitle.isEmpty {
|
||||
alert.addButton(withTitle: secondButtonTitle)
|
||||
}
|
||||
alert.beginSheetModal(for: window) { response in
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 07/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 07/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
@ -2,7 +2,7 @@
|
||||
// LocalNotification.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
@ -2,7 +2,7 @@
|
||||
// ImageGenerator.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
@ -24,7 +24,7 @@ class MenuBarImageGenerator {
|
||||
NSAttributedString.Key.paragraphStyle: textStyle
|
||||
]
|
||||
|
||||
let padding : CGFloat = 2.0;
|
||||
let padding: CGFloat = 2.0
|
||||
|
||||
// Create an attributed string so we'll know how wide the item will need to be
|
||||
let attributedString = NSAttributedString(string: text, attributes: textFontAttributes)
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 05/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 16/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -11,7 +11,7 @@ import Foundation
|
||||
class VersionExtractor {
|
||||
|
||||
/**
|
||||
This attempts to extract the version number from the command line output of Valet.
|
||||
This attempts to extract the version number from any given string.
|
||||
*/
|
||||
public static func from(_ string: String) -> String? {
|
||||
do {
|
||||
@ -23,7 +23,7 @@ class VersionExtractor {
|
||||
let match = regex.matches(
|
||||
in: string,
|
||||
options: [],
|
||||
range: NSMakeRange(0, string.count)
|
||||
range: NSRange(location: 0, length: string.count)
|
||||
).first
|
||||
|
||||
guard let match = match else {
|
||||
|
@ -2,7 +2,7 @@
|
||||
// ActivePhpInstallation.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -35,7 +35,7 @@ class ActivePhpInstallation {
|
||||
getVersion()
|
||||
|
||||
// If an error occurred, exit early
|
||||
if (version.error) {
|
||||
if version.error {
|
||||
limits = Limits()
|
||||
extensions = []
|
||||
return
|
||||
@ -60,9 +60,9 @@ class ActivePhpInstallation {
|
||||
|
||||
// See if any extensions are present in said .ini files
|
||||
paths.forEach { (iniFilePath) in
|
||||
let exts = PhpExtension.load(from: URL(fileURLWithPath: iniFilePath))
|
||||
if exts.count > 0 {
|
||||
extensions.append(contentsOf: exts)
|
||||
let loadedExtensions = PhpExtension.load(from: URL(fileURLWithPath: iniFilePath))
|
||||
if !loadedExtensions.isEmpty {
|
||||
extensions.append(contentsOf: loadedExtensions)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,12 +71,12 @@ class ActivePhpInstallation {
|
||||
When the app tries to retrieve the version, the installation is considered broken if the output is nothing,
|
||||
_or_ if the output contains the word "Warning" or "Error". In normal situations this should not be the case.
|
||||
*/
|
||||
private func getVersion() -> Void {
|
||||
private func getVersion() {
|
||||
self.version = Version()
|
||||
|
||||
let version = Command.execute(path: Paths.phpConfig, arguments: ["--version"], trimNewlines: true)
|
||||
|
||||
if (version == "" || version.contains("Warning") || version.contains("Error")) {
|
||||
if version == "" || version.contains("Warning") || version.contains("Error") {
|
||||
self.version.short = "💩 BROKEN"
|
||||
self.version.long = ""
|
||||
self.version.error = true
|
||||
@ -112,13 +112,13 @@ class ActivePhpInstallation {
|
||||
let value = Command.execute(path: Paths.php, arguments: ["-r", "echo ini_get('\(key)');"])
|
||||
|
||||
// Check if the value is unlimited
|
||||
if (value == "-1") {
|
||||
if value == "-1" {
|
||||
return "∞"
|
||||
}
|
||||
|
||||
// Check if the syntax is valid otherwise
|
||||
let regex = try! NSRegularExpression(pattern: #"^([0-9]*)(K|M|G|)$"#, options: [])
|
||||
let match = regex.matches(in: value, options: [], range: NSMakeRange(0, value.count)).first
|
||||
let match = regex.matches(in: value, options: [], range: NSRange(location: 0, length: value.count)).first
|
||||
return (match == nil) ? "⚠️" : "\(value)B"
|
||||
}
|
||||
|
||||
|
33
phpmon/Common/PHP/Extensions/Xdebug.swift
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// Xdebug.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 01/05/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Xdebug {
|
||||
|
||||
public static var enabled: Bool {
|
||||
return !self.mode.isEmpty
|
||||
}
|
||||
|
||||
public static var mode: String {
|
||||
return Command.execute(path: Paths.php, arguments: ["-r", "echo ini_get('xdebug.mode');"])
|
||||
}
|
||||
|
||||
public static var modes: [String] {
|
||||
return [
|
||||
"off",
|
||||
"develop",
|
||||
"coverage",
|
||||
"debug",
|
||||
"gcstats",
|
||||
"profile",
|
||||
"trace"
|
||||
]
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
// HomebrewPackage.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
@ -20,16 +20,19 @@ struct HomebrewService: Decodable, Equatable {
|
||||
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)
|
||||
})
|
||||
filter: [String] = [PhpEnv.phpInstall.formula, "nginx", "dnsmasq"],
|
||||
completion: @escaping ([HomebrewService]) -> Void
|
||||
) {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
let data = Shell
|
||||
.pipe("sudo \(Paths.brew) services info --all --json", requiresPath: true)
|
||||
.data(using: .utf8)!
|
||||
|
||||
let services = try! JSONDecoder()
|
||||
.decode([HomebrewService].self, from: data)
|
||||
.filter({ return filter.contains($0.name) })
|
||||
|
||||
completion(services)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 21/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -15,7 +15,7 @@ class PhpEnv {
|
||||
init() {
|
||||
self.currentInstall = ActivePhpInstallation()
|
||||
|
||||
let brewPhpAlias = Shell.pipe("\(Paths.brew) info php --json");
|
||||
let brewPhpAlias = Shell.pipe("\(Paths.brew) info php --json")
|
||||
|
||||
self.homebrewPackage = try! JSONDecoder().decode(
|
||||
[HomebrewPackage].self,
|
||||
@ -76,15 +76,14 @@ class PhpEnv {
|
||||
return InternalSwitcher()
|
||||
}
|
||||
|
||||
public static func detectPhpVersions() -> Void {
|
||||
public static func detectPhpVersions() {
|
||||
_ = Self.shared.detectPhpVersions()
|
||||
}
|
||||
|
||||
/**
|
||||
Detects which versions of PHP are installed.
|
||||
*/
|
||||
public func detectPhpVersions() -> [String]
|
||||
{
|
||||
public func detectPhpVersions() -> [String] {
|
||||
let files = Shell.pipe("ls \(Paths.optPath) | grep php@")
|
||||
|
||||
var versionsOnly = extractPhpVersions(from: files.components(separatedBy: "\n"))
|
||||
@ -95,7 +94,7 @@ class PhpEnv {
|
||||
let phpAlias = homebrewPackage.version
|
||||
|
||||
// Avoid inserting a duplicate
|
||||
if (!versionsOnly.contains(phpAlias) && Filesystem.fileExists("\(Paths.optPath)/php/bin/php")) {
|
||||
if !versionsOnly.contains(phpAlias) && Filesystem.fileExists("\(Paths.optPath)/php/bin/php") {
|
||||
versionsOnly.append(phpAlias)
|
||||
}
|
||||
|
||||
@ -117,12 +116,22 @@ class PhpEnv {
|
||||
/**
|
||||
Extracts valid PHP versions from an array of strings.
|
||||
This array of strings is usually retrieved from `grep`.
|
||||
|
||||
If `generateHelpers` is set to true, after detecting
|
||||
all versions, helper scripts are generated as well.
|
||||
*/
|
||||
public func extractPhpVersions(
|
||||
from versions: [String],
|
||||
checkBinaries: Bool = true
|
||||
checkBinaries: Bool = true,
|
||||
generateHelpers: Bool = true
|
||||
) -> [String] {
|
||||
var output : [String] = []
|
||||
var output: [String] = []
|
||||
|
||||
var supported = Constants.SupportedPhpVersions
|
||||
|
||||
if !Valet.enabled(feature: .supportForPhp56) {
|
||||
supported.removeAll { $0 == "5.6" }
|
||||
}
|
||||
|
||||
versions.filter { (version) -> Bool in
|
||||
// Omit everything that doesn't start with php@
|
||||
@ -133,13 +142,16 @@ class PhpEnv {
|
||||
// Only append the version if it doesn't already exist (avoid dupes),
|
||||
// is supported and where the binary exists (avoids broken installs)
|
||||
if !output.contains(version)
|
||||
&& Constants.SupportedPhpVersions.contains(version)
|
||||
&& (checkBinaries ? Filesystem.fileExists("\(Paths.optPath)/php@\(version)/bin/php") : true)
|
||||
{
|
||||
&& supported.contains(version)
|
||||
&& (checkBinaries ? Filesystem.fileExists("\(Paths.optPath)/php@\(version)/bin/php") : true) {
|
||||
output.append(version)
|
||||
}
|
||||
}
|
||||
|
||||
if generateHelpers {
|
||||
output.forEach { PhpHelper.generate(for: $0) }
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
|
61
phpmon/Common/PHP/PHP Version/PhpHelper.swift
Normal file
@ -0,0 +1,61 @@
|
||||
//
|
||||
// PhpHelper.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 17/03/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class PhpHelper {
|
||||
|
||||
static let keyPhrase = "This file was automatically generated by PHP Monitor."
|
||||
|
||||
public static func generate(for version: String) {
|
||||
// Take the PHP version (e.g. "7.2") and generate a dotless version
|
||||
let dotless = version.replacingOccurrences(of: ".", with: "")
|
||||
|
||||
do {
|
||||
let destination = "/usr/local/bin/pm\(dotless)"
|
||||
if FileManager.default.fileExists(atPath: destination) {
|
||||
let contents = try String(contentsOfFile: destination)
|
||||
if !contents.contains(keyPhrase) {
|
||||
Log.info("The file at '\(destination)' already exists and was not generated by PHP Monitor "
|
||||
+ "(or is unreadable). Not updating this file.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Let's follow the symlink to the PHP binary folder
|
||||
let path = URL(fileURLWithPath: "\(Paths.optPath)/php@\(version)/bin")
|
||||
.resolvingSymlinksInPath().path
|
||||
|
||||
// The contents of the script!
|
||||
let script = """
|
||||
#!/bin/zsh
|
||||
# \(keyPhrase)
|
||||
# It reflects the location of PHP \(version)'s binaries on your system.
|
||||
# Usage: . pm\(dotless)
|
||||
[[ $ZSH_EVAL_CONTEXT =~ :file$ ]] \\
|
||||
&& echo "PHP Monitor has enabled this terminal to use PHP \(version)." \\
|
||||
|| echo "You must run '. pm\(dotless)' (or 'source pm\(dotless)') instead!";
|
||||
export PATH=\(path):$PATH
|
||||
"""
|
||||
|
||||
// Write to the destination
|
||||
try script.write(
|
||||
to: URL(fileURLWithPath: destination),
|
||||
atomically: true,
|
||||
encoding: String.Encoding.utf8
|
||||
)
|
||||
|
||||
// Make sure the file is executable
|
||||
Shell.run("chmod +x \(destination)")
|
||||
} catch {
|
||||
print(error)
|
||||
Log.err("Could not write PHP Monitor helper for PHP \(version) to /usr/local/bin/pm\(dotless)")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,7 @@ public struct PhpVersionNumberCollection: Equatable {
|
||||
|
||||
public static func make(from versions: [String]) -> Self {
|
||||
return PhpVersionNumberCollection(
|
||||
versions: versions.map { PhpVersionNumber.make(from: $0)! }
|
||||
versions: versions.map { try! PhpVersionNumber.parse($0) }
|
||||
)
|
||||
}
|
||||
|
||||
@ -134,7 +134,12 @@ public struct PhpVersionNumber: Equatable {
|
||||
|
||||
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
|
||||
|
||||
let match = regex.matches(
|
||||
in: versionString,
|
||||
options: [],
|
||||
range: NSRange(location: 0, length: versionString.count)
|
||||
).first
|
||||
|
||||
if match != nil {
|
||||
let major = Int(
|
||||
@ -143,7 +148,7 @@ public struct PhpVersionNumber: Equatable {
|
||||
let minor = Int(
|
||||
versionString[Range(match!.range(withName: "minor"), in: versionString)!]
|
||||
)!
|
||||
var patch: Int? = nil
|
||||
var patch: Int?
|
||||
if let minorRange = Range(match!.range(withName: "patch"), in: versionString) {
|
||||
patch = Int(versionString[minorRange])
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 31/01/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -23,7 +23,8 @@ class PhpExtension {
|
||||
/// The original string that was used to determine this extension is active.
|
||||
var line: String
|
||||
|
||||
/// The name of the extension. This is always identical to the name found in the original string. If you want to display this name, capitalize this.
|
||||
/// The name of the extension. This is always identical to the name found in the original string.
|
||||
/// If you want to display this name, capitalize this.
|
||||
var name: String
|
||||
|
||||
/// Whether the extension has been enabled.
|
||||
@ -34,6 +35,7 @@ class PhpExtension {
|
||||
return String(file.split(separator: "/").last ?? "php.ini")
|
||||
}
|
||||
|
||||
// swiftlint:disable line_length
|
||||
/**
|
||||
This regular expression will allow us to identify lines which activate an extension.
|
||||
|
||||
@ -47,13 +49,14 @@ class PhpExtension {
|
||||
- Note: Extensions that are disabled in a different way will not be detected. This is intentional.
|
||||
*/
|
||||
static let extensionRegex = #"^(extension|zend_extension|;(\s?)extension|;(\s?)zend_extension)(\s?)(=)(\s?)(?<name>["]?(?:\/?.\/?)+(?:\.so)"?)$"#
|
||||
// swiftlint:enable line_length
|
||||
|
||||
/**
|
||||
When registering an extension, we do that based on the line found inside the .ini file.
|
||||
*/
|
||||
init(_ line: String, file: String) {
|
||||
let regex = try! NSRegularExpression(pattern: Self.extensionRegex, options: [])
|
||||
let match = regex.matches(in: line, options: [], range: NSMakeRange(0, line.count)).first
|
||||
let match = regex.matches(in: line, options: [], range: NSRange(location: 0, length: line.count)).first
|
||||
let range = Range(match!.range(withName: "name"), in: line)!
|
||||
|
||||
self.line = line
|
||||
@ -69,7 +72,8 @@ class PhpExtension {
|
||||
}
|
||||
|
||||
/**
|
||||
This simply toggles the extension in the .ini file. You may need to restart the other services in order for this change to apply.
|
||||
This simply toggles the extension in the .ini file.
|
||||
You may need to restart the other services in order for this change to apply.
|
||||
*/
|
||||
func toggle() {
|
||||
let newLine = enabled
|
||||
@ -91,7 +95,7 @@ class PhpExtension {
|
||||
static func load(from path: URL) -> [PhpExtension] {
|
||||
let file = try? String(contentsOf: path, encoding: .utf8)
|
||||
|
||||
if (file == nil) {
|
||||
if file == nil {
|
||||
Log.err("There was an issue reading the file. Assuming no extensions were found.")
|
||||
return []
|
||||
}
|
||||
|
@ -3,14 +3,14 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 28/11/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class PhpInstallation {
|
||||
|
||||
var longVersion: PhpVersionNumber
|
||||
var versionNumber: PhpVersionNumber
|
||||
|
||||
/**
|
||||
In order to determine details about a PHP installation, we’ll simply run `php-config --version`
|
||||
@ -19,7 +19,7 @@ class PhpInstallation {
|
||||
init(_ version: String) {
|
||||
|
||||
let phpConfigExecutablePath = "\(Paths.optPath)/php@\(version)/bin/php-config"
|
||||
self.longVersion = PhpVersionNumber.make(from: version)!
|
||||
self.versionNumber = PhpVersionNumber.make(from: version)!
|
||||
|
||||
if Filesystem.fileExists(phpConfigExecutablePath) {
|
||||
let longVersionString = Command.execute(
|
||||
@ -29,7 +29,7 @@ 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.
|
||||
self.longVersion = try! PhpVersionNumber.parse(longVersionString)
|
||||
self.versionNumber = try! PhpVersionNumber.parse(longVersionString)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 24/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -20,24 +20,29 @@ class InternalSwitcher: PhpSwitcher {
|
||||
the version that is switched to may or may not be identical to `php`
|
||||
(without @version).
|
||||
*/
|
||||
func performSwitch(to version: String, completion: @escaping () -> Void)
|
||||
{
|
||||
func performSwitch(to version: String, completion: @escaping () -> Void) {
|
||||
Log.info("Switching to \(version), unlinking all versions...")
|
||||
|
||||
let isolated = Valet.shared.sites.filter { site in
|
||||
site.isolatedPhpVersion != nil
|
||||
}.map { site in
|
||||
return site.isolatedPhpVersion!.versionNumber.homebrewVersion
|
||||
}
|
||||
|
||||
var versions: Set<String> = [version]
|
||||
|
||||
if Valet.enabled(feature: .isolatedSites) {
|
||||
versions = versions.union(isolated)
|
||||
}
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
PhpEnv.shared.availablePhpVersions.forEach { (available) in
|
||||
group.enter()
|
||||
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
let formula = (available == PhpEnv.brewPhpVersion)
|
||||
? "php" : "php@\(available)"
|
||||
|
||||
brew("unlink \(formula)")
|
||||
brew("services stop \(formula)", sudo: true)
|
||||
|
||||
Log.perf("Unlinked and stopped services for \(formula)")
|
||||
|
||||
self.disableDefaultPhpFpmPool(available)
|
||||
self.stopPhpVersion(available)
|
||||
group.leave()
|
||||
}
|
||||
}
|
||||
@ -46,16 +51,63 @@ class InternalSwitcher: PhpSwitcher {
|
||||
Log.info("All versions have been unlinked!")
|
||||
Log.info("Linking the new version!")
|
||||
|
||||
let formula = (version == PhpEnv.brewPhpVersion) ? "php" : "php@\(version)"
|
||||
brew("link \(formula) --overwrite --force")
|
||||
brew("services start \(formula)", sudo: true)
|
||||
for formula in versions {
|
||||
self.startPhpVersion(formula, primary: (version == formula))
|
||||
}
|
||||
|
||||
Log.info("Restarting nginx, just to be sure!")
|
||||
brew("services restart nginx", sudo: true)
|
||||
|
||||
Log.info("The new version has been linked!")
|
||||
Log.info("The new version(s) have been linked!")
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
private func disableDefaultPhpFpmPool(_ version: String) {
|
||||
let pool = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf"
|
||||
if FileManager.default.fileExists(atPath: pool) {
|
||||
Log.info("A default `www.conf` file was found in the php-fpm.d directory for PHP \(version).")
|
||||
let existing = URL(string: "file://\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf")!
|
||||
let new = URL(string: "file://\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf.disabled-by-phpmon")!
|
||||
do {
|
||||
if FileManager.default.fileExists(atPath: new.path) {
|
||||
Log.info("A moved `www.conf.disabled-by-phpmon` file was found for PHP \(version), "
|
||||
+ "cleaning up so the newer `www.conf` can be moved again.")
|
||||
try FileManager.default.removeItem(at: new)
|
||||
}
|
||||
try FileManager.default.moveItem(at: existing, to: new)
|
||||
Log.info("Success: A default `www.conf` file was disabled for PHP \(version).")
|
||||
} catch {
|
||||
Log.err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func stopPhpVersion(_ version: String) {
|
||||
let formula = (version == PhpEnv.brewPhpVersion) ? "php" : "php@\(version)"
|
||||
brew("unlink \(formula)")
|
||||
brew("services stop \(formula)", sudo: true)
|
||||
Log.info("Unlinked and stopped services for \(formula)")
|
||||
}
|
||||
|
||||
private func startPhpVersion(_ version: String, primary: Bool) {
|
||||
let formula = (version == PhpEnv.brewPhpVersion) ? "php" : "php@\(version)"
|
||||
|
||||
if primary {
|
||||
Log.info("\(formula) is the primary formula, linking and starting services...")
|
||||
brew("link \(formula) --overwrite --force")
|
||||
} else {
|
||||
Log.info("\(formula) is an isolated PHP version, starting services only...")
|
||||
}
|
||||
|
||||
brew("services start \(formula)", sudo: true)
|
||||
|
||||
if Valet.enabled(feature: .isolatedSites) && primary {
|
||||
let socketVersion = version.replacingOccurrences(of: ".", with: "")
|
||||
Shell.run("ln -sF ~/.config/valet/valet\(socketVersion).sock ~/.config/valet/valet.sock")
|
||||
Log.info("Symlinked new socket version (valet\(socketVersion).sock → valet.sock).")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 24/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 05/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
@ -38,7 +38,7 @@ extension App {
|
||||
If there are no windows open, the app will be an accessory (toolbar) app.
|
||||
*/
|
||||
public func updateActivationPolicy() {
|
||||
NSApp.setActivationPolicy(openWindows.count > 0 ? .regular : .accessory)
|
||||
NSApp.setActivationPolicy(!openWindows.isEmpty ? .regular : .accessory)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,10 +3,9 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 05/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import HotKey
|
||||
import Cocoa
|
||||
|
||||
extension App {
|
||||
|
@ -2,11 +2,10 @@
|
||||
// StateManager.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import HotKey
|
||||
|
||||
class App {
|
||||
|
||||
@ -22,6 +21,16 @@ class App {
|
||||
return "\(version) (\(build))"
|
||||
}
|
||||
|
||||
/** Just the bundle version (build). */
|
||||
static var bundleVersion: String {
|
||||
return Bundle.main.infoDictionary?["CFBundleVersion"] as! String
|
||||
}
|
||||
|
||||
/** Just the version number. */
|
||||
static var shortVersion: String {
|
||||
return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String
|
||||
}
|
||||
|
||||
static var architecture: String {
|
||||
var systeminfo = utsname()
|
||||
uname(&systeminfo)
|
||||
@ -42,10 +51,10 @@ class App {
|
||||
var preferences: [PreferenceName: Bool]!
|
||||
|
||||
/** The window controller of the currently active preferences window. */
|
||||
var preferencesWindowController: PrefsWC? = nil
|
||||
var preferencesWindowController: PrefsWC?
|
||||
|
||||
/** The window controller of the currently active site list window. */
|
||||
var siteListWindowController: SiteListWC? = nil
|
||||
var domainListWindowController: DomainListWC?
|
||||
|
||||
/** List of detected (installed) applications that PHP Monitor can work with. */
|
||||
var detectedApplications: [Application] = []
|
||||
@ -58,7 +67,7 @@ class App {
|
||||
/**
|
||||
The shortcut the user has requested.
|
||||
*/
|
||||
var shortcutHotkey: HotKey? = nil {
|
||||
var shortcutHotkey: HotKey? {
|
||||
didSet {
|
||||
setupGlobalHotkeyListener()
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 20/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
@ -44,4 +44,3 @@ extension AppDelegate {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 05/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -26,19 +26,19 @@ extension AppDelegate {
|
||||
// MARK: - Menu Interactions
|
||||
|
||||
@IBAction func addSiteLinkPressed(_ sender: Any) {
|
||||
SiteListVC.show()
|
||||
DomainListVC.show()
|
||||
|
||||
guard let windowController = App.shared.siteListWindowController else { return }
|
||||
guard let windowController = App.shared.domainListWindowController else { return }
|
||||
windowController.pressedAddLink(nil)
|
||||
}
|
||||
|
||||
@IBAction func reloadSiteListPressed(_ sender: Any) {
|
||||
let vc = App.shared.siteListWindowController?
|
||||
.window?.contentViewController as? SiteListVC
|
||||
@IBAction func reloadDomainListPressed(_ sender: Any) {
|
||||
let vc = App.shared.domainListWindowController?
|
||||
.window?.contentViewController as? DomainListVC
|
||||
|
||||
if vc != nil {
|
||||
// If the view exists, directly reload the list of sites
|
||||
vc!.reloadSites()
|
||||
vc!.reloadDomains()
|
||||
} else {
|
||||
// If the view does not exist, reload the cached data that was populated when the app initially launched.
|
||||
Valet.shared.reloadSites()
|
||||
@ -46,9 +46,9 @@ extension AppDelegate {
|
||||
}
|
||||
|
||||
@IBAction func focusSearchField(_ sender: Any) {
|
||||
SiteListVC.show()
|
||||
DomainListVC.show()
|
||||
|
||||
guard let windowController = App.shared.siteListWindowController else { return }
|
||||
guard let windowController = App.shared.domainListWindowController else { return }
|
||||
windowController.searchToolbarItem.searchField.becomeFirstResponder()
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 06/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
@ -2,7 +2,7 @@
|
||||
// AppDelegate.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
@ -67,6 +67,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
#if DEBUG
|
||||
logger.verbosity = .performance
|
||||
#endif
|
||||
if CommandLine.arguments.contains("--v") {
|
||||
logger.verbosity = .performance
|
||||
Log.info("Extra verbose mode has been activated.")
|
||||
}
|
||||
Log.separator(as: .info)
|
||||
Log.info("PHP MONITOR by Nico Verbruggen")
|
||||
Log.info("Version \(App.version)")
|
||||
|
181
phpmon/Domain/App/AppUpdateChecker.swift
Normal file
@ -0,0 +1,181 @@
|
||||
//
|
||||
// Updater.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 09/05/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AppKit
|
||||
|
||||
class AppUpdateChecker {
|
||||
|
||||
public static var enabled: Bool = {
|
||||
return Preferences.isEnabled(.automaticBackgroundUpdateCheck)
|
||||
}()
|
||||
|
||||
public static var isDev: Bool = {
|
||||
return App.version.contains("-dev")
|
||||
}()
|
||||
|
||||
public static func retrieveVersionFromCask(
|
||||
_ initiatedFromBackground: Bool = true
|
||||
) -> String {
|
||||
let caskFile = App.version.contains("-dev")
|
||||
? Constants.Urls.DevBuildCaskFile.absoluteString
|
||||
: Constants.Urls.StableBuildCaskFile.absoluteString
|
||||
|
||||
var command = "curl -s"
|
||||
|
||||
if initiatedFromBackground {
|
||||
command = "curl -s --max-time 5"
|
||||
}
|
||||
|
||||
return Shell.pipe(
|
||||
"\(command) '\(caskFile)' | grep version"
|
||||
)
|
||||
}
|
||||
|
||||
public static func checkIfNewerVersionIsAvailable(
|
||||
initiatedFromBackground: Bool = true
|
||||
) {
|
||||
if initiatedFromBackground {
|
||||
if !Preferences.isEnabled(.automaticBackgroundUpdateCheck) {
|
||||
Log.info("Automatic updates are disabled. No check will be performed.")
|
||||
return
|
||||
}
|
||||
|
||||
Log.info("Automatic updates are enabled, a check will be performed.")
|
||||
}
|
||||
|
||||
let versionString = retrieveVersionFromCask(initiatedFromBackground)
|
||||
|
||||
guard let onlineVersion = AppVersion.from(versionString) else {
|
||||
Log.err("We couldn't check for updates!")
|
||||
|
||||
// Only notify about connection issues if the request to check for updates was explicit
|
||||
if !initiatedFromBackground {
|
||||
notifyAboutConnectionIssue()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let currentVersion = AppVersion.fromCurrentVersion()
|
||||
|
||||
handleVersionComparison(
|
||||
currentVersion,
|
||||
onlineVersion,
|
||||
initiatedFromBackground
|
||||
)
|
||||
}
|
||||
|
||||
private static func handleVersionComparison(
|
||||
_ currentVersion: AppVersion,
|
||||
_ onlineVersion: AppVersion,
|
||||
_ background: Bool
|
||||
) {
|
||||
switch onlineVersion.version.versionCompare(currentVersion.version) {
|
||||
case .orderedAscending:
|
||||
Log.info("You are running a newer version of PHP Monitor "
|
||||
+ "(\(currentVersion.computerReadable) > \(onlineVersion.computerReadable)).")
|
||||
if !background { notifyVersionDoesNotNeedUpgrade() }
|
||||
case .orderedDescending:
|
||||
Log.info("There is a newer version (\(onlineVersion)) available! "
|
||||
+ "(\(onlineVersion.computerReadable) > \(currentVersion.computerReadable))")
|
||||
notifyAboutNewerVersion(version: onlineVersion)
|
||||
case .orderedSame:
|
||||
if currentVersion.build != nil
|
||||
&& onlineVersion.build != nil
|
||||
&& buildDiffers(currentVersion, onlineVersion, background) {
|
||||
return
|
||||
}
|
||||
|
||||
Log.info("The installed version (\(currentVersion.computerReadable)) matches the latest release "
|
||||
+ "(\(onlineVersion.computerReadable)).")
|
||||
if !background { notifyVersionDoesNotNeedUpgrade() }
|
||||
}
|
||||
}
|
||||
|
||||
private static func buildDiffers(
|
||||
_ currentVersion: AppVersion,
|
||||
_ onlineVersion: AppVersion,
|
||||
_ background: Bool
|
||||
) -> Bool {
|
||||
if Int(onlineVersion.build!)! > Int(currentVersion.build!)! {
|
||||
Log.info("There is a newer build of PHP Monitor available! "
|
||||
+ "(\(onlineVersion.computerReadable) > \(currentVersion.computerReadable))")
|
||||
notifyAboutNewerVersion(version: onlineVersion)
|
||||
return true
|
||||
} else if Int(onlineVersion.build!)! < Int(currentVersion.build!)! {
|
||||
Log.info("You are running a newer build of PHP Monitor "
|
||||
+ "(\(currentVersion.computerReadable) > \(onlineVersion.computerReadable)).")
|
||||
if !background { notifyVersionDoesNotNeedUpgrade() }
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private static func notifyVersionDoesNotNeedUpgrade() {
|
||||
DispatchQueue.main.async {
|
||||
BetterAlert().withInformation(
|
||||
title: "updater.alerts.is_latest_version.title".localized,
|
||||
subtitle: "updater.alerts.is_latest_version.subtitle".localized(App.shortVersion),
|
||||
description: ""
|
||||
)
|
||||
.withPrimary(text: "OK")
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private static func notifyAboutNewerVersion(version: AppVersion) {
|
||||
let devSuffix = isDev ? "-dev" : ""
|
||||
let command = isDev ? "brew upgrade phpmon-dev" : "brew upgrade phpmon"
|
||||
|
||||
DispatchQueue.main.async {
|
||||
BetterAlert().withInformation(
|
||||
title: "updater.alerts.newer_version_available.title".localized(version.humanReadable),
|
||||
subtitle: "updater.alerts.newer_version_available.subtitle".localized,
|
||||
description: HomebrewDiagnostics.customCaskInstalled
|
||||
? "updater.installation_source.brew".localized(command)
|
||||
: "updater.installation_source.direct".localized
|
||||
)
|
||||
.withPrimary(
|
||||
text: "updater.alerts.buttons.release_notes".localized,
|
||||
action: { vc in
|
||||
vc.close(with: .OK)
|
||||
NSWorkspace.shared.open(
|
||||
Constants.Urls.GitHubReleases.appendingPathComponent("/tag/v\(version.version)\(devSuffix)")
|
||||
)
|
||||
}
|
||||
)
|
||||
.withTertiary(text: "Dismiss", action: { vc in
|
||||
vc.close(with: .OK)
|
||||
})
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private static func notifyAboutConnectionIssue() {
|
||||
DispatchQueue.main.async {
|
||||
BetterAlert().withInformation(
|
||||
title: "updater.errors.cannot_check_for_update.title".localized,
|
||||
subtitle: "updater.errors.cannot_check_for_update.subtitle".localized,
|
||||
description: "updater.errors.cannot_check_for_update.description".localized(
|
||||
App.version
|
||||
)
|
||||
)
|
||||
.withTertiary(
|
||||
text: "updater.errors.buttons.releases_on_github".localized,
|
||||
action: { _ in
|
||||
NSWorkspace.shared.open(Constants.Urls.GitHubReleases)
|
||||
}
|
||||
)
|
||||
.withPrimary(text: "OK")
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
77
phpmon/Domain/App/AppVersion.swift
Normal file
@ -0,0 +1,77 @@
|
||||
//
|
||||
// AppVersion.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 10/05/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class AppVersion {
|
||||
var version: String
|
||||
var build: String?
|
||||
var suffix: String?
|
||||
|
||||
init(version: String, build: String?, suffix: String? = nil) {
|
||||
self.version = version
|
||||
self.build = build
|
||||
self.suffix = suffix
|
||||
}
|
||||
|
||||
public static func from(_ string: String) -> AppVersion? {
|
||||
do {
|
||||
let regex = try NSRegularExpression(
|
||||
pattern: #"(?<version>(\d+)[.](\d+)([.](\d+))?)(-(?<suffix>[a-z]+)){0,1}((,|_)(?<build>\d+)){0,1}"#,
|
||||
options: []
|
||||
)
|
||||
|
||||
let match = regex.matches(
|
||||
in: string,
|
||||
options: [],
|
||||
range: NSRange(location: 0, length: string.count)
|
||||
).first
|
||||
|
||||
guard let match = match else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var version: String = ""
|
||||
var build: String?
|
||||
var suffix: String?
|
||||
|
||||
if let versionRange = Range(match.range(withName: "version"), in: string) {
|
||||
version = String(string[versionRange])
|
||||
}
|
||||
|
||||
if let buildRange = Range(match.range(withName: "build"), in: string) {
|
||||
build = String(string[buildRange])
|
||||
}
|
||||
|
||||
if let suffixRange = Range(match.range(withName: "suffix"), in: string) {
|
||||
suffix = String(string[suffixRange])
|
||||
}
|
||||
|
||||
return AppVersion(
|
||||
version: version,
|
||||
build: build,
|
||||
suffix: suffix
|
||||
)
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public static func fromCurrentVersion() -> AppVersion {
|
||||
return AppVersion.from("\(App.shortVersion)_\(App.bundleVersion)")!
|
||||
}
|
||||
|
||||
var computerReadable: String {
|
||||
return "\(version)_\(build ?? "0")"
|
||||
}
|
||||
|
||||
var humanReadable: String {
|
||||
return "\(version) (\(build ?? "???"))"
|
||||
}
|
||||
|
||||
}
|
@ -23,7 +23,7 @@ class InterApp {
|
||||
|
||||
static func getCommands() -> [InterApp.Action] { return [
|
||||
InterApp.Action(command: "list", action: { _ in
|
||||
SiteListVC.show()
|
||||
DomainListVC.show()
|
||||
}),
|
||||
InterApp.Action(command: "services/stop", action: { _ in
|
||||
MainMenu.shared.stopAllServices()
|
||||
@ -61,7 +61,7 @@ class InterApp {
|
||||
subtitle: "PHP Monitor can't switch to PHP \(version), as it may not be installed or available."
|
||||
).withPrimary(text: "OK").show()
|
||||
}
|
||||
}),
|
||||
})
|
||||
]}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Environment.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -17,8 +17,7 @@ class Startup {
|
||||
If this method returns false, there was a failed check and an alert was displayed.
|
||||
If this method returns true, then all checks succeeded and the app can continue.
|
||||
*/
|
||||
func checkEnvironment() async -> Bool
|
||||
{
|
||||
func checkEnvironment() async -> Bool {
|
||||
// Do the important system setup checks
|
||||
Log.info("[ARCH] The user is running PHP Monitor with the architecture: \(App.architecture)")
|
||||
|
||||
@ -166,6 +165,23 @@ class Startup {
|
||||
descriptionText: "startup.errors.services_json_error.desc".localized
|
||||
),
|
||||
// =================================================================================
|
||||
// Determine that the Valet configuration JSON file is valid.
|
||||
// =================================================================================
|
||||
EnvironmentCheck(
|
||||
command: {
|
||||
// Detect additional binaries (e.g. Composer)
|
||||
Paths.shared.detectBinaryPaths()
|
||||
// Load the configuration file (config.json)
|
||||
Valet.shared.loadConfiguration()
|
||||
// This check fails when the config is nil
|
||||
return Valet.shared.config == nil
|
||||
},
|
||||
name: "`config.json` was valid",
|
||||
titleText: "startup.errors.valet_json_invalid.title".localized,
|
||||
subtitleText: "startup.errors.valet_json_invalid.subtitle".localized,
|
||||
descriptionText: "startup.errors.valet_json_invalid.desc".localized
|
||||
),
|
||||
// =================================================================================
|
||||
// Determine the Valet version and ensure it isn't unknown.
|
||||
// =================================================================================
|
||||
EnvironmentCheck(
|
||||
|
169
phpmon/Domain/DomainList/AddProxyVC.swift
Normal file
@ -0,0 +1,169 @@
|
||||
//
|
||||
// AddSiteVC.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 24/01/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Cocoa
|
||||
|
||||
class AddProxyVC: NSViewController, NSTextFieldDelegate {
|
||||
|
||||
// MARK: - Outlets
|
||||
|
||||
@IBOutlet weak var textFieldTitle: NSTextField!
|
||||
@IBOutlet weak var textFieldProxySubject: NSTextField!
|
||||
@IBOutlet weak var textFieldDomainName: NSTextField!
|
||||
|
||||
@IBOutlet weak var inputProxySubject: NSTextField!
|
||||
@IBOutlet weak var inputDomainName: NSTextField!
|
||||
|
||||
@IBOutlet weak var previewText: NSTextField!
|
||||
|
||||
@IBOutlet weak var buttonSecure: NSButton!
|
||||
@IBOutlet weak var buttonCreateProxy: NSButton!
|
||||
@IBOutlet weak var buttonCancel: NSButton!
|
||||
|
||||
@IBOutlet weak var textFieldSecure: NSTextField!
|
||||
@IBOutlet weak var textFieldError: NSTextField!
|
||||
|
||||
// MARK: - View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
loadStaticLocalisedStrings()
|
||||
|
||||
buttonCreateProxy.isEnabled = false
|
||||
updatePreview()
|
||||
validate()
|
||||
}
|
||||
|
||||
private func dismissView(outcome: NSApplication.ModalResponse) {
|
||||
guard let window = view.window, let parent = window.sheetParent else { return }
|
||||
parent.endSheet(window, returnCode: outcome)
|
||||
}
|
||||
|
||||
// MARK: - Localisation
|
||||
|
||||
func loadStaticLocalisedStrings() {
|
||||
textFieldTitle.stringValue = "domain_list.add.set_up_proxy".localized
|
||||
textFieldProxySubject.stringValue = "domain_list.add.proxy_subject".localized
|
||||
textFieldDomainName.stringValue = "domain_list.add.domain_name".localized
|
||||
textFieldSecure.stringValue = "domain_list.add.secure_description".localized
|
||||
buttonCancel.title = "domain_list.add.cancel".localized
|
||||
buttonCreateProxy.title = "domain_list.add.create_proxy".localized
|
||||
}
|
||||
|
||||
// MARK: - Outlet Interactions
|
||||
|
||||
@IBAction func pressedSecure(_ sender: Any) {
|
||||
updatePreview()
|
||||
}
|
||||
|
||||
@IBAction func pressedCreateProxy(_ sender: Any) {
|
||||
let domain = self.inputDomainName.stringValue
|
||||
let proxyName = self.inputProxySubject.stringValue
|
||||
let secure = self.buttonSecure.state == .on ? " --secure" : ""
|
||||
|
||||
dismissView(outcome: .OK)
|
||||
|
||||
App.shared.domainListWindowController?.contentVC.setUIBusy()
|
||||
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
Shell.run("\(Paths.valet) proxy \(domain) \(proxyName)\(secure)", requiresPath: true)
|
||||
Actions.restartNginx()
|
||||
|
||||
DispatchQueue.main.async {
|
||||
App.shared.domainListWindowController?.contentVC.setUINotBusy()
|
||||
App.shared.domainListWindowController?.pressedReload(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func pressedCancel(_ sender: Any) {
|
||||
dismissView(outcome: .cancel)
|
||||
}
|
||||
|
||||
// MARK: - Text Field Delegate
|
||||
|
||||
func controlTextDidChange(_ obj: Notification) {
|
||||
updateTextField()
|
||||
}
|
||||
|
||||
// MARK: - Helper Methods
|
||||
|
||||
private func validate() {
|
||||
_ = validate(
|
||||
domain: inputDomainName.stringValue,
|
||||
proxy: inputProxySubject.stringValue
|
||||
)
|
||||
}
|
||||
|
||||
private func validate(domain: String, proxy: String) -> Bool {
|
||||
if proxy.isEmpty {
|
||||
textFieldError.isHidden = false
|
||||
textFieldError.stringValue = "domain_list.add.errors.empty_proxy".localized
|
||||
return false
|
||||
}
|
||||
|
||||
if proxy.range(of: #"(http:\/\/|https:\/\/)(.+)(:)(\d+)$"#, options: .regularExpression) == nil {
|
||||
textFieldError.isHidden = false
|
||||
textFieldError.stringValue = "domain_list.add.errors.subject_invalid".localized
|
||||
return false
|
||||
}
|
||||
|
||||
if domain.isEmpty {
|
||||
textFieldError.isHidden = false
|
||||
textFieldError.stringValue = "domain_list.add.errors.empty".localized
|
||||
return false
|
||||
}
|
||||
|
||||
if Valet.shared.sites.contains(where: { $0.name == domain }) {
|
||||
textFieldError.isHidden = false
|
||||
textFieldError.stringValue = "domain_list.add.errors.already_exists".localized
|
||||
return false
|
||||
}
|
||||
|
||||
textFieldError.isHidden = true
|
||||
return true
|
||||
}
|
||||
|
||||
func updateTextField() {
|
||||
inputDomainName.stringValue = inputDomainName.stringValue
|
||||
.replacingOccurrences(of: " ", with: "-")
|
||||
|
||||
inputProxySubject.stringValue = inputProxySubject.stringValue
|
||||
.replacingOccurrences(of: " ", with: "-")
|
||||
|
||||
buttonCreateProxy.isEnabled = validate(
|
||||
domain: inputDomainName.stringValue,
|
||||
proxy: inputProxySubject.stringValue
|
||||
)
|
||||
|
||||
updatePreview()
|
||||
}
|
||||
|
||||
func updatePreview() {
|
||||
buttonSecure.title = "domain_list.add.secure_after_creation"
|
||||
.localized(
|
||||
inputDomainName.stringValue,
|
||||
Valet.shared.config.tld
|
||||
)
|
||||
|
||||
if inputProxySubject.stringValue.isEmpty || inputDomainName.stringValue.isEmpty {
|
||||
previewText.stringValue = "domain_list.add.empty_fields".localized
|
||||
return
|
||||
}
|
||||
|
||||
previewText.stringValue = "domain_list.add.proxy_available"
|
||||
.localized(
|
||||
inputProxySubject.stringValue,
|
||||
buttonSecure.state == .on ? "https" : "http",
|
||||
inputDomainName.stringValue,
|
||||
Valet.shared.config.tld
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -11,14 +11,19 @@ import Cocoa
|
||||
|
||||
class AddSiteVC: NSViewController, NSTextFieldDelegate {
|
||||
|
||||
// MARK: - Outlets
|
||||
|
||||
@IBOutlet weak var textFieldTitle: NSTextField!
|
||||
|
||||
@IBOutlet weak var pathControl: NSPathControl!
|
||||
@IBOutlet weak var linkName: NSTextField!
|
||||
@IBOutlet weak var inputDomainName: NSTextField!
|
||||
|
||||
@IBOutlet weak var previewText: NSTextField!
|
||||
|
||||
@IBOutlet weak var buttonSecure: NSButton!
|
||||
@IBOutlet weak var buttonCreateLink: NSButton!
|
||||
@IBOutlet weak var buttonCancel: NSButton!
|
||||
|
||||
@IBOutlet weak var textFieldTitle: NSTextField!
|
||||
@IBOutlet weak var textFieldSecure: NSTextField!
|
||||
@IBOutlet weak var textFieldError: NSTextField!
|
||||
|
||||
@ -37,43 +42,46 @@ class AddSiteVC: NSViewController, NSTextFieldDelegate {
|
||||
// MARK: - Localisation
|
||||
|
||||
func loadStaticLocalisedStrings() {
|
||||
textFieldTitle.stringValue = "site_list.add.link_folder".localized
|
||||
linkName.placeholderString = "site_list.add.domain_name_placeholder".localized
|
||||
textFieldSecure.stringValue = "site_list.add.secure_description".localized
|
||||
buttonCancel.stringValue = "site_list.add.cancel".localized
|
||||
textFieldTitle.stringValue = "domain_list.add.link_folder".localized
|
||||
inputDomainName.placeholderString = "domain_list.add.domain_name_placeholder".localized
|
||||
textFieldSecure.stringValue = "domain_list.add.secure_description".localized
|
||||
buttonCancel.title = "domain_list.add.cancel".localized
|
||||
buttonCreateLink.title = "domain_list.add.create_link".localized
|
||||
}
|
||||
|
||||
// MARK: - Outlet Interactions
|
||||
|
||||
@IBAction func pressedCreateLink(_ sender: Any) {
|
||||
let path = self.pathControl.url!.path
|
||||
let name = self.linkName.stringValue
|
||||
let path = pathControl.url!.path
|
||||
let name = inputDomainName.stringValue
|
||||
|
||||
if !FileManager.default.fileExists(atPath: path) {
|
||||
Alert.confirm(
|
||||
onWindow: self.view.window!,
|
||||
messageText: "site_list.alert.folder_missing.title".localized,
|
||||
informativeText: "site_list.alert.folder_missing.desc".localized,
|
||||
buttonTitle: "site_list.alert.folder_missing.cancel".localized,
|
||||
secondButtonTitle: "site_list.alert.folder_missing.return".localized,
|
||||
onFirstButtonPressed: {
|
||||
self.dismissView(outcome: .cancel)
|
||||
onWindow: view.window!,
|
||||
messageText: "domain_list.alert.folder_missing.title".localized,
|
||||
informativeText: "domain_list.alert.folder_missing.desc".localized,
|
||||
buttonTitle: "domain_list.alert.folder_missing.cancel".localized,
|
||||
secondButtonTitle: "domain_list.alert.folder_missing.return".localized,
|
||||
onFirstButtonPressed: { [self] in
|
||||
dismissView(outcome: .cancel)
|
||||
}
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
Shell.run("cd '\(path)' && \(Paths.valet) link '\(name)'", requiresPath: true)
|
||||
// Adding `valet links` is a workaround for Valet malforming the config.json file
|
||||
// TODO: I will have to investigate and report this behaviour if possible
|
||||
Shell.run("cd '\(path)' && \(Paths.valet) link '\(name)' && valet links", requiresPath: true)
|
||||
|
||||
self.dismissView(outcome: .OK)
|
||||
dismissView(outcome: .OK)
|
||||
|
||||
// Reset search
|
||||
App.shared.siteListWindowController?
|
||||
App.shared.domainListWindowController?
|
||||
.searchToolbarItem
|
||||
.searchField.stringValue = ""
|
||||
|
||||
// Add the new item and scrolls to it
|
||||
App.shared.siteListWindowController?
|
||||
App.shared.domainListWindowController?
|
||||
.contentVC
|
||||
.addedNewSite(
|
||||
name: name,
|
||||
@ -82,7 +90,7 @@ class AddSiteVC: NSViewController, NSTextFieldDelegate {
|
||||
}
|
||||
|
||||
@IBAction func pressedCancel(_ sender: Any) {
|
||||
self.dismissView(outcome: .cancel)
|
||||
dismissView(outcome: .cancel)
|
||||
}
|
||||
|
||||
@IBAction func pressedSecure(_ sender: Any) {
|
||||
@ -98,41 +106,46 @@ class AddSiteVC: NSViewController, NSTextFieldDelegate {
|
||||
// MARK: - Helper Methods
|
||||
|
||||
private func isValidLinkName(_ name: String) -> Bool {
|
||||
if self.linkName.stringValue.isEmpty {
|
||||
self.textFieldError.isHidden = false
|
||||
self.textFieldError.stringValue = "site_list.add.errors.empty".localized
|
||||
if name.isEmpty {
|
||||
textFieldError.isHidden = false
|
||||
textFieldError.stringValue = "domain_list.add.errors.empty".localized
|
||||
return false
|
||||
}
|
||||
|
||||
if Valet.shared.sites.contains(where: { $0.name == name }) {
|
||||
self.textFieldError.isHidden = false
|
||||
self.textFieldError.stringValue = "site_list.add.errors.already_exists".localized
|
||||
textFieldError.isHidden = false
|
||||
textFieldError.stringValue = "domain_list.add.errors.already_exists".localized
|
||||
return false
|
||||
}
|
||||
|
||||
self.textFieldError.isHidden = true
|
||||
textFieldError.isHidden = true
|
||||
return true
|
||||
}
|
||||
|
||||
func updateTextField() {
|
||||
self.linkName.stringValue = self.linkName.stringValue
|
||||
inputDomainName.stringValue = inputDomainName.stringValue
|
||||
.replacingOccurrences(of: " ", with: "-")
|
||||
|
||||
buttonCreateLink.isEnabled = isValidLinkName(self.linkName.stringValue)
|
||||
self.updatePreview()
|
||||
buttonCreateLink.isEnabled = isValidLinkName(inputDomainName.stringValue)
|
||||
updatePreview()
|
||||
}
|
||||
|
||||
func updatePreview() {
|
||||
buttonSecure.title = "site_list.add.secure_after_creation"
|
||||
buttonSecure.title = "domain_list.add.secure_after_creation"
|
||||
.localized(
|
||||
self.linkName.stringValue,
|
||||
inputDomainName.stringValue,
|
||||
Valet.shared.config.tld
|
||||
)
|
||||
|
||||
previewText.stringValue = "site_list.add.folder_available"
|
||||
if inputDomainName.stringValue.isEmpty {
|
||||
previewText.stringValue = "domain_list.add.empty_fields".localized
|
||||
return
|
||||
}
|
||||
|
||||
previewText.stringValue = "domain_list.add.folder_available"
|
||||
.localized(
|
||||
self.buttonSecure.state == .on ? "https" : "http",
|
||||
self.linkName.stringValue,
|
||||
buttonSecure.state == .on ? "https" : "http",
|
||||
inputDomainName.stringValue,
|
||||
Valet.shared.config.tld
|
||||
)
|
||||
}
|
15
phpmon/Domain/DomainList/Cells/DomainListCellProtocol.swift
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// DomainListCellProtocol.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 03/12/2021.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import AppKit
|
||||
|
||||
protocol DomainListCellProtocol {
|
||||
func populateCell(with site: ValetSite)
|
||||
func populateCell(with proxy: ValetProxy)
|
||||
}
|
36
phpmon/Domain/DomainList/Cells/DomainListKindCell.swift
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// DomainListTypeCell.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 16/03/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import AppKit
|
||||
|
||||
class DomainListKindCell: NSTableCellView, DomainListCellProtocol {
|
||||
static let reusableName = "domainListKindCell"
|
||||
|
||||
@IBOutlet weak var imageViewType: NSImageView!
|
||||
|
||||
func populateCell(with site: ValetSite) {
|
||||
// If the `aliasPath` is nil, we're dealing with a parked site (otherwise: linked).
|
||||
imageViewType.image = NSImage(
|
||||
named: site.aliasPath == nil
|
||||
? "IconParked"
|
||||
: "IconLinked"
|
||||
)
|
||||
|
||||
// Unless, of course, this is a default site
|
||||
if site.absolutePath == Valet.shared.config.defaultSite {
|
||||
imageViewType.image = NSImage(named: "IconDefault")
|
||||
}
|
||||
|
||||
imageViewType.contentTintColor = NSColor.tertiaryLabelColor
|
||||
}
|
||||
|
||||
func populateCell(with proxy: ValetProxy) {
|
||||
imageViewType.image = NSImage(named: "IconProxy")
|
||||
}
|
||||
}
|
27
phpmon/Domain/DomainList/Cells/DomainListNameCell.swift
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// DomainListNameCell.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 16/03/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import AppKit
|
||||
|
||||
class DomainListNameCell: NSTableCellView, DomainListCellProtocol {
|
||||
static let reusableName = "domainListNameCell"
|
||||
|
||||
@IBOutlet weak var labelSiteName: NSTextField!
|
||||
@IBOutlet weak var labelPathName: NSTextField!
|
||||
|
||||
func populateCell(with site: ValetSite) {
|
||||
labelSiteName.stringValue = "\(site.name).\(site.tld)"
|
||||
labelPathName.stringValue = site.absolutePathRelative
|
||||
}
|
||||
|
||||
func populateCell(with proxy: ValetProxy) {
|
||||
labelSiteName.stringValue = "\(proxy.domain).\(proxy.tld)"
|
||||
labelPathName.stringValue = proxy.target
|
||||
}
|
||||
}
|
102
phpmon/Domain/DomainList/Cells/DomainListPhpCell.swift
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// DomainListPhpCell.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 16/03/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import AppKit
|
||||
|
||||
class DomainListPhpCell: NSTableCellView, DomainListCellProtocol {
|
||||
static let reusableName = "domainListPhpCell"
|
||||
|
||||
var site: ValetSite?
|
||||
|
||||
@IBOutlet weak var buttonPhpVersion: NSButton!
|
||||
@IBOutlet weak var imageViewPhpVersionOK: NSImageView!
|
||||
|
||||
func populateCell(with site: ValetSite) {
|
||||
self.site = site
|
||||
|
||||
buttonPhpVersion.isHidden = false
|
||||
imageViewPhpVersionOK.isHidden = false
|
||||
|
||||
buttonPhpVersion.title = " PHP \(site.servingPhpVersion)"
|
||||
|
||||
imageViewPhpVersionOK.toolTip = nil
|
||||
|
||||
if site.isolatedPhpVersion != nil {
|
||||
imageViewPhpVersionOK.isHidden = false
|
||||
imageViewPhpVersionOK.image = NSImage(named: "Isolated")
|
||||
imageViewPhpVersionOK.toolTip = "domain_list.tooltips.isolated".localized(site.servingPhpVersion)
|
||||
} else {
|
||||
imageViewPhpVersionOK.isHidden = (site.composerPhp == "???" || !site.composerPhpCompatibleWithLinked)
|
||||
imageViewPhpVersionOK.image = NSImage(named: "Checkmark")
|
||||
imageViewPhpVersionOK.toolTip = "domain_list.tooltips.checkmark".localized(site.composerPhp)
|
||||
}
|
||||
}
|
||||
|
||||
func populateCell(with proxy: ValetProxy) {
|
||||
buttonPhpVersion.isHidden = true
|
||||
imageViewPhpVersionOK.isHidden = true
|
||||
return
|
||||
}
|
||||
|
||||
@IBAction func pressedPhpVersion(_ sender: Any) {
|
||||
guard let site = self.site else { return }
|
||||
|
||||
let alert = NSAlert.init()
|
||||
alert.alertStyle = .informational
|
||||
|
||||
var information = ""
|
||||
|
||||
if self.site?.isolatedPhpVersion != nil {
|
||||
information += "alert.composer_php_isolated.desc".localized(
|
||||
self.site!.isolatedPhpVersion!.versionNumber.homebrewVersion,
|
||||
PhpEnv.phpInstall.version.short
|
||||
)
|
||||
information += "\n\n"
|
||||
}
|
||||
|
||||
information += "alert.composer_php_requirement.type.\(site.composerPhpSource.rawValue)"
|
||||
.localized
|
||||
|
||||
alert.messageText = "alert.composer_php_requirement.title"
|
||||
.localized("\(site.name).\(Valet.shared.config.tld)", site.composerPhp)
|
||||
alert.informativeText = information
|
||||
|
||||
alert.addButton(withTitle: "site_link.close".localized)
|
||||
|
||||
var mapIndex: Int = NSApplication.ModalResponse.alertSecondButtonReturn.rawValue
|
||||
var map: [Int: String] = [:]
|
||||
|
||||
if site.isolatedPhpVersion == nil {
|
||||
// Determine which installed versions would be ideal to switch to,
|
||||
// but make sure to exclude the currently linked version
|
||||
PhpEnv.shared.validVersions(for: site.composerPhp).filter({ version in
|
||||
version.homebrewVersion != PhpEnv.phpInstall.version.short
|
||||
}).forEach { version in
|
||||
alert.addButton(withTitle: "site_link.switch_to_php".localized(version.homebrewVersion))
|
||||
map[mapIndex] = version.homebrewVersion
|
||||
mapIndex += 1
|
||||
}
|
||||
|
||||
// Site is not isolated, show options to switch global PHP version
|
||||
alert.beginSheetModal(for: App.shared.domainListWindowController!.window!) { response in
|
||||
if response.rawValue > NSApplication.ModalResponse.alertFirstButtonReturn.rawValue {
|
||||
if map.keys.contains(response.rawValue) {
|
||||
let version = map[response.rawValue]!
|
||||
Log.info("Pressed button to switch to \(version)")
|
||||
MainMenu.shared.switchToPhpVersion(version)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Site is isolated, do not show any options to switch
|
||||
alert.beginSheetModal(for: App.shared.domainListWindowController!.window!)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
28
phpmon/Domain/DomainList/Cells/DomainListTLSCell.swift
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// DomainListNameCell.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 16/03/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import AppKit
|
||||
|
||||
class DomainListTLSCell: NSTableCellView, DomainListCellProtocol {
|
||||
static let reusableName = "domainListTLSCell"
|
||||
|
||||
@IBOutlet weak var imageViewLock: NSImageView!
|
||||
|
||||
func populateCell(with site: ValetSite) {
|
||||
imageViewLock.contentTintColor = site.secured
|
||||
? NSColor(named: "IconColorGreen")
|
||||
: NSColor(named: "IconColorRed")
|
||||
}
|
||||
|
||||
func populateCell(with proxy: ValetProxy) {
|
||||
imageViewLock.contentTintColor = proxy.secured
|
||||
? NSColor(named: "IconColorGreen")
|
||||
: NSColor(named: "IconColorRed")
|
||||
}
|
||||
}
|
36
phpmon/Domain/DomainList/Cells/DomainListTypeCell.swift
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// DomainListTypeCell.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 16/03/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import AppKit
|
||||
|
||||
class DomainListTypeCell: NSTableCellView, DomainListCellProtocol {
|
||||
static let reusableName = "domainListTypeCell"
|
||||
|
||||
@IBOutlet weak var labelDriver: NSTextField!
|
||||
@IBOutlet weak var labelPhpVersion: NSTextField!
|
||||
|
||||
func populateCell(with site: ValetSite) {
|
||||
labelDriver.stringValue = site.driver ?? "driver.not_detected".localized
|
||||
|
||||
// Determine the Laravel version
|
||||
if site.driver == "Laravel" && site.notableComposerDependencies.keys.contains("laravel/framework") {
|
||||
let constraint = site.notableComposerDependencies["laravel/framework"]!
|
||||
labelDriver.stringValue = "Laravel (\(constraint))"
|
||||
}
|
||||
|
||||
// PHP version
|
||||
labelPhpVersion.stringValue = site.composerPhp == "???" ? "Any PHP" : "PHP \(site.composerPhp)"
|
||||
}
|
||||
|
||||
func populateCell(with proxy: ValetProxy) {
|
||||
labelDriver.stringValue = "Proxy"
|
||||
labelPhpVersion.stringValue = "Active"
|
||||
return
|
||||
}
|
||||
}
|
200
phpmon/Domain/DomainList/DomainListVC+Actions.swift
Normal file
@ -0,0 +1,200 @@
|
||||
//
|
||||
// DomainListVC+Actions.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 23/12/2021.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Cocoa
|
||||
|
||||
extension DomainListVC {
|
||||
|
||||
@objc func toggleSecure() {
|
||||
if selected is ValetSite {
|
||||
toggleSecureForSite()
|
||||
} else {
|
||||
toggleSecureForProxy()
|
||||
}
|
||||
}
|
||||
|
||||
func toggleSecureForProxy() {
|
||||
let originalSecureStatus = selectedProxy!.secured
|
||||
let selectedProxy = selectedProxy!
|
||||
|
||||
self.waitAndExecute {
|
||||
// 1. Remove the original proxy
|
||||
Shell.run("\(Paths.valet) unproxy \(selectedProxy.domain)", requiresPath: true)
|
||||
|
||||
// 2. Add a new proxy, which is either secured/unsecured
|
||||
let secure = originalSecureStatus ? "" : " --secure"
|
||||
Shell.run("\(Paths.valet) proxy \(selectedProxy.domain) \(selectedProxy.target)\(secure)",
|
||||
requiresPath: true)
|
||||
|
||||
// 3. Restart nginx
|
||||
Actions.restartNginx()
|
||||
|
||||
// 4. Reload site list
|
||||
DispatchQueue.main.async {
|
||||
App.shared.domainListWindowController?.pressedReload(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toggleSecureForSite() {
|
||||
let rowToReload = tableView.selectedRow
|
||||
let originalSecureStatus = selectedSite!.secured
|
||||
let action = selectedSite!.secured ? "unsecure" : "secure"
|
||||
let selectedSite = selectedSite!
|
||||
let command = "cd '\(selectedSite.absolutePath)' && sudo \(Paths.valet) \(action) && exit;"
|
||||
|
||||
waitAndExecute {
|
||||
Shell.run(command, requiresPath: true)
|
||||
} completion: { [self] in
|
||||
selectedSite.determineSecured()
|
||||
if selectedSite.secured == originalSecureStatus {
|
||||
BetterAlert()
|
||||
.withInformation(
|
||||
title: "domain_list.alerts_status_not_changed.title".localized,
|
||||
subtitle: "domain_list.alerts_status_not_changed.desc".localized(command)
|
||||
)
|
||||
.withPrimary(text: "OK")
|
||||
.show()
|
||||
} else {
|
||||
let newState = selectedSite.secured ? "secured" : "unsecured"
|
||||
LocalNotification.send(
|
||||
title: "domain_list.alerts_status_changed.title".localized,
|
||||
subtitle: "domain_list.alerts_status_changed.desc"
|
||||
.localized(
|
||||
"\(selectedSite.name).\(Valet.shared.config.tld)",
|
||||
newState
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
tableView.reloadData(forRowIndexes: [rowToReload], columnIndexes: [0, 1, 2, 3, 4])
|
||||
tableView.deselectRow(rowToReload)
|
||||
tableView.selectRowIndexes([rowToReload], byExtendingSelection: true)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func openInBrowser() {
|
||||
guard let selected = self.selected else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let url = selected.getListableUrl() else {
|
||||
BetterAlert()
|
||||
.withInformation(
|
||||
title: "domain_list.alert.invalid_folder_name".localized,
|
||||
subtitle: "domain_list.alert.invalid_folder_name_desc".localized
|
||||
)
|
||||
.withPrimary(text: "OK")
|
||||
.show()
|
||||
return
|
||||
}
|
||||
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
|
||||
@objc func openInFinder() {
|
||||
Shell.run("open '\(selectedSite!.absolutePath)'")
|
||||
}
|
||||
|
||||
@objc func openInTerminal() {
|
||||
Shell.run("open -b com.apple.terminal '\(selectedSite!.absolutePath)'")
|
||||
}
|
||||
|
||||
@objc func openWithEditor(sender: EditorMenuItem) {
|
||||
guard let editor = sender.editor else { return }
|
||||
editor.openDirectory(file: selectedSite!.absolutePath)
|
||||
}
|
||||
|
||||
@objc func isolateSite(sender: PhpMenuItem) {
|
||||
let command = "sudo \(Paths.valet) isolate php@\(sender.version) --site '\(self.selectedSite!.name)' && exit;"
|
||||
|
||||
self.performAction(command: command) {
|
||||
self.selectedSite!.determineIsolated()
|
||||
|
||||
if self.selectedSite!.isolatedPhpVersion == nil {
|
||||
BetterAlert()
|
||||
.withInformation(
|
||||
title: "domain_list.alerts_isolation_failed.title".localized,
|
||||
subtitle: "domain_list.alerts_isolation_failed.subtitle".localized,
|
||||
description: "domain_list.alerts_isolation_failed.desc".localized(command)
|
||||
)
|
||||
.withPrimary(text: "OK")
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func removeIsolatedSite() {
|
||||
self.performAction(command: "sudo \(Paths.valet) unisolate --site '\(self.selectedSite!.name)' && exit;") {
|
||||
self.selectedSite!.isolatedPhpVersion = nil
|
||||
}
|
||||
}
|
||||
|
||||
@objc func unlinkSite() {
|
||||
guard let site = selectedSite else {
|
||||
return
|
||||
}
|
||||
|
||||
if site.aliasPath == nil {
|
||||
return
|
||||
}
|
||||
|
||||
Alert.confirm(
|
||||
onWindow: view.window!,
|
||||
messageText: "domain_list.confirm_unlink".localized(site.name),
|
||||
informativeText: "domain_list.confirm_unlink_desc".localized,
|
||||
buttonTitle: "domain_list.unlink".localized,
|
||||
secondButtonTitle: "Cancel",
|
||||
style: .critical,
|
||||
onFirstButtonPressed: {
|
||||
self.waitAndExecute {
|
||||
Shell.run("valet unlink '\(site.name)'", requiresPath: true)
|
||||
} completion: {
|
||||
self.reloadDomains()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@objc func removeProxy() {
|
||||
guard let proxy = selectedProxy else {
|
||||
return
|
||||
}
|
||||
|
||||
Alert.confirm(
|
||||
onWindow: view.window!,
|
||||
messageText: "domain_list.confirm_unproxy".localized("\(proxy.domain).\(proxy.tld)"),
|
||||
informativeText: "domain_list.confirm_unproxy_desc".localized,
|
||||
buttonTitle: "domain_list.unproxy".localized,
|
||||
secondButtonTitle: "Cancel",
|
||||
style: .critical,
|
||||
onFirstButtonPressed: {
|
||||
self.waitAndExecute {
|
||||
Shell.run("valet unproxy '\(proxy.domain)'", requiresPath: true)
|
||||
} completion: {
|
||||
self.reloadDomains()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private func performAction(command: String, beforeCellReload: @escaping () -> Void) {
|
||||
let rowToReload = tableView.selectedRow
|
||||
|
||||
waitAndExecute {
|
||||
Shell.run(command, requiresPath: true)
|
||||
} completion: { [self] in
|
||||
beforeCellReload()
|
||||
tableView.reloadData(forRowIndexes: [rowToReload], columnIndexes: [0, 1, 2, 3, 4])
|
||||
tableView.deselectRow(rowToReload)
|
||||
tableView.selectRowIndexes([rowToReload], byExtendingSelection: true)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
176
phpmon/Domain/DomainList/DomainListVC+ContextMenu.swift
Normal file
@ -0,0 +1,176 @@
|
||||
//
|
||||
// DomainListVC+ContextMenu.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 10/12/2021.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
extension DomainListVC {
|
||||
|
||||
internal func reloadContextMenu() {
|
||||
guard let selected = selected else {
|
||||
tableView.menu = nil
|
||||
return
|
||||
}
|
||||
|
||||
if let selected = selected as? ValetSite {
|
||||
addMenuItemsForSite(selected)
|
||||
return
|
||||
}
|
||||
if let selected = selected as? ValetProxy {
|
||||
addMenuItemsForProxy(selected)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Menu Items for Site
|
||||
|
||||
private func addMenuItemsForSite(_ site: ValetSite) {
|
||||
let menu = NSMenu()
|
||||
|
||||
addSystemApps(to: menu)
|
||||
addSeparator(to: menu)
|
||||
addDetectedApps(to: menu)
|
||||
addSeparator(to: menu)
|
||||
|
||||
if Valet.enabled(feature: .isolatedSites) {
|
||||
addIsolate(to: menu, with: site)
|
||||
} else {
|
||||
addDisabledIsolation(to: menu)
|
||||
}
|
||||
|
||||
addUnlink(to: menu, with: site)
|
||||
addToggleSecure(to: menu, secured: site.secured)
|
||||
|
||||
tableView.menu = menu
|
||||
}
|
||||
|
||||
private func addSystemApps(to menu: NSMenu) {
|
||||
menu.addItem(withTitle: "domain_list.system_apps".localized, action: nil, keyEquivalent: "")
|
||||
menu.addItem(
|
||||
withTitle: "domain_list.open_in_finder".localized,
|
||||
action: #selector(self.openInFinder),
|
||||
keyEquivalent: "F"
|
||||
)
|
||||
menu.addItem(
|
||||
withTitle: "domain_list.open_in_terminal".localized,
|
||||
action: #selector(self.openInTerminal),
|
||||
keyEquivalent: "T"
|
||||
)
|
||||
menu.addItem(
|
||||
withTitle: "domain_list.open_in_browser".localized,
|
||||
action: #selector(self.openInBrowser),
|
||||
keyEquivalent: "B"
|
||||
)
|
||||
}
|
||||
|
||||
private func addDetectedApps(to menu: NSMenu) {
|
||||
if !applications.isEmpty {
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
menu.addItem(withTitle: "domain_list.detected_apps".localized, action: nil, keyEquivalent: "")
|
||||
|
||||
for editor in applications {
|
||||
let editorMenuItem = EditorMenuItem(
|
||||
title: "Open with \(editor.name)",
|
||||
action: #selector(self.openWithEditor(sender:)),
|
||||
keyEquivalent: ""
|
||||
)
|
||||
editorMenuItem.editor = editor
|
||||
menu.addItem(editorMenuItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func addUnlink(to menu: NSMenu, with site: ValetSite) {
|
||||
if site.aliasPath != nil {
|
||||
menu.addItem(
|
||||
withTitle: "domain_list.unlink".localized,
|
||||
action: #selector(self.unlinkSite),
|
||||
keyEquivalent: ""
|
||||
)
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
}
|
||||
}
|
||||
|
||||
private func addDisabledIsolation(to menu: NSMenu) {
|
||||
menu.addItem(withTitle: "domain_list.isolation_unavailable".localized, action: nil, keyEquivalent: "")
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
}
|
||||
|
||||
private func addIsolate(to menu: NSMenu, with site: ValetSite) {
|
||||
if site.isolatedPhpVersion == nil {
|
||||
// ISOLATION POSSIBLE
|
||||
let isolationMenuItem = NSMenuItem(title: "domain_list.isolate".localized, action: nil, keyEquivalent: "")
|
||||
let submenu = NSMenu()
|
||||
submenu.addItem(withTitle: "Choose a PHP version", action: nil, keyEquivalent: "")
|
||||
for version in PhpEnv.shared.availablePhpVersions.reversed() {
|
||||
let item = PhpMenuItem(
|
||||
title: "Always use PHP \(version)",
|
||||
action: #selector(self.isolateSite),
|
||||
keyEquivalent: ""
|
||||
)
|
||||
item.version = version
|
||||
submenu.addItem(item)
|
||||
}
|
||||
menu.setSubmenu(submenu, for: isolationMenuItem)
|
||||
|
||||
menu.addItem(isolationMenuItem)
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
} else {
|
||||
// REMOVE ISOLATION POSSIBLE
|
||||
menu.addItem(
|
||||
withTitle: "domain_list.remove_isolation".localized,
|
||||
action: #selector(self.removeIsolatedSite),
|
||||
keyEquivalent: ""
|
||||
)
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
}
|
||||
}
|
||||
|
||||
private func addToggleSecure(to menu: NSMenu, secured: Bool) {
|
||||
menu.addItem(
|
||||
withTitle: secured
|
||||
? "domain_list.unsecure".localized
|
||||
: "domain_list.secure".localized,
|
||||
action: #selector(toggleSecure),
|
||||
keyEquivalent: ""
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Menu Items for Proxy
|
||||
|
||||
private func addMenuItemsForProxy(_ proxy: ValetProxy) {
|
||||
let menu = NSMenu()
|
||||
addOpenProxyInBrowser(to: menu)
|
||||
addSeparator(to: menu)
|
||||
addToggleSecure(to: menu, secured: proxy.secured)
|
||||
addRemoveProxy(to: menu)
|
||||
tableView.menu = menu
|
||||
}
|
||||
|
||||
private func addOpenProxyInBrowser(to menu: NSMenu) {
|
||||
menu.addItem(
|
||||
withTitle: "domain_list.open_in_browser".localized,
|
||||
action: #selector(self.openInBrowser),
|
||||
keyEquivalent: "B"
|
||||
)
|
||||
}
|
||||
|
||||
private func addRemoveProxy(to menu: NSMenu) {
|
||||
menu.addItem(
|
||||
withTitle: "domain_list.unproxy".localized,
|
||||
action: #selector(self.removeProxy),
|
||||
keyEquivalent: ""
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Shared
|
||||
|
||||
private func addSeparator(to menu: NSMenu) {
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +1,15 @@
|
||||
//
|
||||
// SiteListVC.swift
|
||||
// DomainListVC.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 30/03/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import HotKey
|
||||
import Carbon
|
||||
|
||||
class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
|
||||
// MARK: - Outlets
|
||||
|
||||
@ -20,13 +19,16 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
// MARK: - Variables
|
||||
|
||||
/// List of sites that will be displayed in this view. Originates from the `Valet` object.
|
||||
var sites: [ValetSite] = []
|
||||
var domains: [DomainListable] = []
|
||||
|
||||
/// Array that contains various apps that might open a particular site directory.
|
||||
var applications: [Application] {
|
||||
return App.shared.detectedApplications
|
||||
}
|
||||
|
||||
/// The last sort descriptor used.
|
||||
var sortDescriptor: NSSortDescriptor?
|
||||
|
||||
/// String that was last searched for. Empty by default.
|
||||
var lastSearchedFor = ""
|
||||
|
||||
@ -36,39 +38,53 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
if tableView.selectedRow == -1 {
|
||||
return nil
|
||||
}
|
||||
return sites[tableView.selectedRow]
|
||||
return domains[tableView.selectedRow] as? ValetSite
|
||||
}
|
||||
|
||||
var timer: Timer? = nil
|
||||
var selectedProxy: ValetProxy? {
|
||||
if tableView.selectedRow == -1 {
|
||||
return nil
|
||||
}
|
||||
return domains[tableView.selectedRow] as? ValetProxy
|
||||
}
|
||||
|
||||
var selected: DomainListable? {
|
||||
if tableView.selectedRow == -1 {
|
||||
return nil
|
||||
}
|
||||
return domains[tableView.selectedRow]
|
||||
}
|
||||
|
||||
var timer: Timer?
|
||||
|
||||
// MARK: - Display
|
||||
|
||||
public static func create(delegate: NSWindowDelegate?) {
|
||||
let storyboard = NSStoryboard(name: "Main" , bundle : nil)
|
||||
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||
|
||||
let windowController = storyboard.instantiateController(
|
||||
withIdentifier: "siteListWindow"
|
||||
) as! SiteListWC
|
||||
withIdentifier: "domainListWindow"
|
||||
) as! DomainListWC
|
||||
|
||||
windowController.window!.title = "site_list.title".localized
|
||||
windowController.window!.subtitle = "site_list.subtitle".localized
|
||||
windowController.window!.title = "domain_list.title".localized
|
||||
windowController.window!.subtitle = "domain_list.subtitle".localized
|
||||
windowController.window!.delegate = delegate
|
||||
windowController.window!.styleMask = [
|
||||
.titled, .closable, .resizable, .miniaturizable
|
||||
]
|
||||
windowController.window!.minSize = NSSize(width: 550, height: 200)
|
||||
windowController.window!.delegate = windowController
|
||||
windowController.window!.setFrameAutosaveName("siteListWindow")
|
||||
windowController.window!.setFrameAutosaveName("domainListWindow")
|
||||
|
||||
App.shared.siteListWindowController = windowController
|
||||
App.shared.domainListWindowController = windowController
|
||||
}
|
||||
|
||||
public static func show(delegate: NSWindowDelegate? = nil) {
|
||||
if (App.shared.siteListWindowController == nil) {
|
||||
if App.shared.domainListWindowController == nil {
|
||||
Self.create(delegate: delegate)
|
||||
}
|
||||
|
||||
App.shared.siteListWindowController!.showWindow(self)
|
||||
App.shared.domainListWindowController!.showWindow(self)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
}
|
||||
|
||||
@ -76,12 +92,13 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
|
||||
override func viewDidLoad() {
|
||||
tableView.doubleAction = #selector(self.doubleClicked(sender:))
|
||||
|
||||
if !Valet.shared.sites.isEmpty {
|
||||
// Preloaded list
|
||||
sites = Valet.shared.sites
|
||||
domains = Valet.getDomainListable()
|
||||
searchedFor(text: lastSearchedFor)
|
||||
} else {
|
||||
reloadSites()
|
||||
reloadDomains()
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +108,7 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
Disables the UI so the user cannot interact with it.
|
||||
Also shows a spinner to indicate that we're busy.
|
||||
*/
|
||||
private func setUIBusy() {
|
||||
public func setUIBusy() {
|
||||
// If it takes more than 0.5s to set the UI to not busy, show a spinner
|
||||
timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: { _ in
|
||||
self.progressIndicator.startAnimation(true)
|
||||
@ -105,7 +122,7 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
/**
|
||||
Re-enables the UI so the user can interact with it.
|
||||
*/
|
||||
private func setUINotBusy() {
|
||||
public func setUINotBusy() {
|
||||
timer?.invalidate()
|
||||
progressIndicator.stopAnimation(nil)
|
||||
tableView.alphaValue = 1.0
|
||||
@ -120,8 +137,7 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
- Parameter execute: Callback of the work that needs to happen.
|
||||
- Parameter completion: Callback that is fired when the work is done.
|
||||
*/
|
||||
internal func waitAndExecute(_ execute: @escaping () -> Void, completion: @escaping () -> Void = {})
|
||||
{
|
||||
internal func waitAndExecute(_ execute: @escaping () -> Void, completion: @escaping () -> Void = {}) {
|
||||
setUIBusy()
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
execute()
|
||||
@ -136,15 +152,32 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
|
||||
// MARK: - Site Data Loading
|
||||
|
||||
func reloadSites() {
|
||||
func reloadDomains() {
|
||||
waitAndExecute {
|
||||
Valet.shared.reloadSites()
|
||||
} completion: { [self] in
|
||||
sites = Valet.shared.sites
|
||||
domains = Valet.shared.sites
|
||||
searchedFor(text: lastSearchedFor)
|
||||
}
|
||||
}
|
||||
|
||||
func applySortDescriptor(_ descriptor: NSSortDescriptor) {
|
||||
sortDescriptor = descriptor
|
||||
|
||||
var sorted = self.domains
|
||||
|
||||
switch descriptor.key {
|
||||
case "Secure": sorted = self.domains.sorted { $0.getListableSecured() && !$1.getListableSecured() }
|
||||
case "Domain": sorted = self.domains.sorted { $0.getListableAbsolutePath() < $1.getListableAbsolutePath() }
|
||||
case "PHP": sorted = self.domains.sorted { $0.getListablePhpVersion() < $1.getListablePhpVersion() }
|
||||
case "Kind": sorted = self.domains.sorted { $0.getListableKind() < $1.getListableKind() }
|
||||
case "Type": sorted = self.domains.sorted { $0.getListableType() < $1.getListableType() }
|
||||
default: break
|
||||
}
|
||||
|
||||
self.domains = descriptor.ascending ? sorted.reversed() : sorted
|
||||
}
|
||||
|
||||
func addedNewSite(name: String, secure: Bool) {
|
||||
waitAndExecute {
|
||||
Valet.shared.reloadSites()
|
||||
@ -154,13 +187,13 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
}
|
||||
|
||||
private func find(_ name: String, _ secure: Bool = false) {
|
||||
sites = Valet.shared.sites
|
||||
domains = Valet.getDomainListable()
|
||||
searchedFor(text: "")
|
||||
if let site = sites.enumerated().first(where: { $0.element.name == name }) {
|
||||
if let site = domains.enumerated().first(where: { $0.element.getListableName() == name }) {
|
||||
DispatchQueue.main.async {
|
||||
self.tableView.selectRowIndexes([site.offset], byExtendingSelection: false)
|
||||
self.tableView.scrollRowToVisible(site.offset)
|
||||
if (secure && !site.element.secured) {
|
||||
if secure && !site.element.getListableSecured() {
|
||||
self.toggleSecure()
|
||||
}
|
||||
}
|
||||
@ -170,17 +203,41 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
// MARK: - Table View Delegate
|
||||
|
||||
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||
return sites.count
|
||||
return domains.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
|
||||
guard let sortDescriptor = tableView.sortDescriptors.first else { return }
|
||||
// Kinda scuffed way of applying sort descriptors here, but it works.
|
||||
Log.info("Applying sort descriptor for column: \(sortDescriptor.key ?? "Unknown")")
|
||||
applySortDescriptor(sortDescriptor)
|
||||
searchedFor(text: lastSearchedFor)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||
guard let userCell = tableView.makeView(
|
||||
withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "siteItem"), owner: self
|
||||
) as? SiteListCell else { return nil }
|
||||
let mapping: [String: String] = [
|
||||
"TLS": DomainListTLSCell.reusableName,
|
||||
"DOMAIN": DomainListNameCell.reusableName,
|
||||
"ENVIRONMENT": DomainListPhpCell.reusableName,
|
||||
"KIND": DomainListKindCell.reusableName,
|
||||
"TYPE": DomainListTypeCell.reusableName
|
||||
]
|
||||
|
||||
userCell.populateCell(with: sites[row])
|
||||
let columnName = tableColumn!.identifier.rawValue
|
||||
let identifier = NSUserInterfaceItemIdentifier(rawValue: mapping[columnName]!)
|
||||
|
||||
return userCell
|
||||
guard let userCell = tableView.makeView(withIdentifier: identifier, owner: self)
|
||||
as? DomainListCellProtocol else { return nil }
|
||||
|
||||
if let site = domains[row] as? ValetSite {
|
||||
userCell.populateCell(with: site)
|
||||
}
|
||||
|
||||
if let proxy = domains[row] as? ValetProxy {
|
||||
userCell.populateCell(with: proxy)
|
||||
}
|
||||
|
||||
return userCell as? NSView
|
||||
}
|
||||
|
||||
func tableViewSelectionDidChange(_ notification: Notification) {
|
||||
@ -188,7 +245,7 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
}
|
||||
|
||||
@objc func doubleClicked(sender: Any) {
|
||||
guard self.selectedSite != nil else {
|
||||
guard self.selected != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -197,17 +254,26 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
|
||||
// MARK: - (Search) Text Field Delegate
|
||||
|
||||
func reloadTable() {
|
||||
if let sortDescriptor = sortDescriptor {
|
||||
self.applySortDescriptor(sortDescriptor)
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
func searchedFor(text: String) {
|
||||
lastSearchedFor = text
|
||||
|
||||
let searchString = text.lowercased()
|
||||
|
||||
if searchString.isEmpty {
|
||||
sites = Valet.shared.sites
|
||||
domains = Valet.getDomainListable()
|
||||
|
||||
reloadTable()
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -215,20 +281,18 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
.split(separator: " ")
|
||||
.map { return String($0) }
|
||||
|
||||
sites = Valet.shared.sites.filter({ site in
|
||||
domains = Valet.getDomainListable().filter({ site in
|
||||
return !splitSearchString.map { searchString in
|
||||
return site.name.lowercased().contains(searchString)
|
||||
return site.getListableName().lowercased().contains(searchString)
|
||||
}.contains(false)
|
||||
})
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
reloadTable()
|
||||
}
|
||||
|
||||
// MARK: - Deinitialization
|
||||
|
||||
deinit {
|
||||
Log.perf("SiteListVC deallocated")
|
||||
Log.perf("DomainListVC deallocated")
|
||||
}
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
//
|
||||
// SiteListWC.swift
|
||||
// DomainListWC.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 03/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class SiteListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate {
|
||||
class DomainListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate {
|
||||
|
||||
// MARK: - Window Identifier
|
||||
|
||||
override var windowName: String {
|
||||
return "SiteList"
|
||||
return "DomainList"
|
||||
}
|
||||
|
||||
// MARK: - Outlets
|
||||
@ -30,8 +30,8 @@ class SiteListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate {
|
||||
|
||||
// MARK: - Search functionality
|
||||
|
||||
var contentVC: SiteListVC {
|
||||
return self.contentViewController as! SiteListVC
|
||||
var contentVC: DomainListVC {
|
||||
return self.contentViewController as! DomainListVC
|
||||
}
|
||||
|
||||
var searchTimer: Timer?
|
||||
@ -51,18 +51,43 @@ class SiteListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate {
|
||||
// MARK: - Reload functionality
|
||||
|
||||
@IBAction func pressedReload(_ sender: Any?) {
|
||||
contentVC.reloadSites()
|
||||
contentVC.reloadDomains()
|
||||
}
|
||||
|
||||
@IBAction func pressedAddLink(_ sender: Any?) {
|
||||
selectFolder()
|
||||
showSelectionWindow()
|
||||
}
|
||||
|
||||
// MARK: - Add a new site
|
||||
|
||||
func selectFolder() {
|
||||
func showSelectionWindow() {
|
||||
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||
|
||||
let windowController = storyboard.instantiateController(
|
||||
withIdentifier: "showSelectionWindow"
|
||||
) as! NSWindowController
|
||||
|
||||
let viewController = windowController.window!
|
||||
.contentViewController as! SelectionVC
|
||||
|
||||
viewController.domainListWC = self
|
||||
|
||||
self.window?.beginSheet(windowController.window!)
|
||||
}
|
||||
|
||||
func startCreateLinkFlow() {
|
||||
self.showFolderSelectionForLink()
|
||||
}
|
||||
|
||||
func startCreateProxyFlow() {
|
||||
self.showProxyPopup()
|
||||
}
|
||||
|
||||
// MARK: - Popups
|
||||
|
||||
private func showFolderSelectionForLink() {
|
||||
let dialog = NSOpenPanel()
|
||||
dialog.message = "site_list.add.modal_description".localized
|
||||
dialog.message = "domain_list.add.modal_description".localized
|
||||
dialog.showsResizeIndicator = true
|
||||
dialog.showsHiddenFiles = false
|
||||
dialog.allowsMultipleSelection = false
|
||||
@ -70,15 +95,15 @@ class SiteListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate {
|
||||
dialog.canChooseFiles = false
|
||||
dialog.beginSheetModal(for: self.window!) { response in
|
||||
let result = dialog.url
|
||||
if (result != nil && response == .OK) {
|
||||
if result != nil && response == .OK {
|
||||
let path: String = result!.path
|
||||
self.showSitePopup(path)
|
||||
self.showLinkPopup(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showSitePopup(_ folder: String) {
|
||||
let storyboard = NSStoryboard(name: "Main", bundle : nil)
|
||||
private func showLinkPopup(_ folder: String) {
|
||||
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||
|
||||
let windowController = storyboard.instantiateController(
|
||||
withIdentifier: "addSiteWindow"
|
||||
@ -86,9 +111,21 @@ class SiteListWC: PMWindowController, NSSearchFieldDelegate, NSToolbarDelegate {
|
||||
|
||||
let viewController = windowController.window!.contentViewController as! AddSiteVC
|
||||
viewController.pathControl.url = URL(fileURLWithPath: folder)
|
||||
viewController.linkName.stringValue = String(folder.split(separator: "/").last!)
|
||||
viewController.inputDomainName.stringValue = String(folder.split(separator: "/").last!)
|
||||
viewController.updateTextField()
|
||||
|
||||
self.window?.beginSheet(windowController.window!)
|
||||
}
|
||||
|
||||
private func showProxyPopup() {
|
||||
let storyboard = NSStoryboard(name: "Main", bundle: nil)
|
||||
|
||||
let windowController = storyboard.instantiateController(
|
||||
withIdentifier: "addProxyWindow"
|
||||
) as! NSWindowController
|
||||
|
||||
// let viewController = windowController.window!.contentViewController as! AddSiteVC
|
||||
|
||||
self.window?.beginSheet(windowController.window!)
|
||||
}
|
||||
}
|
62
phpmon/Domain/DomainList/SelectionVC.swift
Normal file
@ -0,0 +1,62 @@
|
||||
//
|
||||
// SelectionVC.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 14/04/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Cocoa
|
||||
|
||||
class SelectionVC: NSViewController {
|
||||
|
||||
weak var domainListWC: DomainListWC?
|
||||
|
||||
@IBOutlet weak var textFieldTitle: NSTextField!
|
||||
@IBOutlet weak var textFieldDescription: NSTextField!
|
||||
@IBOutlet weak var buttonCreateLink: NSButton!
|
||||
@IBOutlet weak var buttonCreateProxy: NSButton!
|
||||
@IBOutlet weak var buttonCancel: NSButton!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
loadStaticLocalisedStrings()
|
||||
}
|
||||
|
||||
override func viewDidAppear() {
|
||||
view.window?.makeFirstResponder(buttonCreateLink)
|
||||
}
|
||||
|
||||
private func dismissView(outcome: NSApplication.ModalResponse) {
|
||||
guard let window = self.view.window, let parent = window.sheetParent else { return }
|
||||
parent.endSheet(window, returnCode: outcome)
|
||||
}
|
||||
|
||||
// MARK: - Localisation
|
||||
|
||||
func loadStaticLocalisedStrings() {
|
||||
textFieldTitle.stringValue = "selection.title".localized
|
||||
textFieldDescription.stringValue = "selection.description".localized
|
||||
buttonCancel.title = "selection.cancel".localized
|
||||
buttonCreateLink.title = "selection.create_link".localized
|
||||
buttonCreateProxy.title = "selection.create_proxy".localized
|
||||
}
|
||||
|
||||
// MARK: - Outlet Interactions
|
||||
|
||||
@IBAction func pressedCreateLink(_ sender: Any) {
|
||||
self.dismissView(outcome: .continue)
|
||||
domainListWC?.startCreateLinkFlow()
|
||||
}
|
||||
|
||||
@IBAction func pressedCreateProxy(_ sender: Any) {
|
||||
self.dismissView(outcome: .continue)
|
||||
domainListWC?.startCreateProxyFlow()
|
||||
}
|
||||
|
||||
@IBAction func pressedCancel(_ sender: Any) {
|
||||
self.dismissView(outcome: .cancel)
|
||||
}
|
||||
|
||||
}
|
@ -16,8 +16,8 @@ struct ComposerJson: Decodable {
|
||||
|
||||
// MARK: - JSON structure
|
||||
|
||||
let dependencies: Dictionary<String, String>?
|
||||
let devDependencies: Dictionary<String, String>?
|
||||
let dependencies: [String: String]?
|
||||
let devDependencies: [String: String]?
|
||||
let configuration: Config?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
@ -40,8 +40,7 @@ struct ComposerJson: Decodable {
|
||||
Checks what the PHP version constraint is.
|
||||
Returns a tuple (constraint, location of constraint).
|
||||
*/
|
||||
public func getPhpVersion() -> (String, ValetSite.VersionSource)
|
||||
{
|
||||
public func getPhpVersion() -> (String, ValetSite.VersionSource) {
|
||||
// Check if in platform
|
||||
if configuration?.platform?.php != nil {
|
||||
return (configuration!.platform!.php!, .platform)
|
||||
@ -76,5 +75,3 @@ struct ComposerJson: Decodable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,10 +10,10 @@ import Foundation
|
||||
|
||||
class ComposerWindow {
|
||||
|
||||
private var menu: MainMenu? = nil
|
||||
private var menu: MainMenu?
|
||||
private var shouldNotify: Bool! = nil
|
||||
private var completion: ((Bool) -> Void)! = nil
|
||||
private var window: ProgressWindowController? = nil
|
||||
private var window: ProgressWindowController?
|
||||
|
||||
/**
|
||||
Updates the global dependencies and runs the completion callback when done.
|
||||
@ -80,7 +80,7 @@ class ComposerWindow {
|
||||
// Closing the window should happen after a slight delay
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [self] in
|
||||
window?.close()
|
||||
if (shouldNotify) {
|
||||
if shouldNotify {
|
||||
LocalNotification.send(
|
||||
title: "alert.composer_success.title".localized,
|
||||
subtitle: "alert.composer_success.info".localized
|
||||
|
@ -17,7 +17,7 @@ struct PhpFrameworks {
|
||||
public static let DependencyList = [
|
||||
|
||||
// COMMON FRAMEWORKS
|
||||
"laravel/framework" : "Laravel",
|
||||
"laravel/framework": "Laravel",
|
||||
"symfony/symfony": "Symfony",
|
||||
"laravel/lumen": "Lumen",
|
||||
|
||||
@ -36,9 +36,10 @@ struct PhpFrameworks {
|
||||
"statamic/cms": "Statamic",
|
||||
"johnpbloch/wordpress-core": "WordPress",
|
||||
"zendframework/zendframework": "Zend",
|
||||
"zendframework/zend-mvc": "Zend"
|
||||
"zendframework/zend-mvc": "Zend",
|
||||
"typo3/cms-core": "Typo3"
|
||||
|
||||
// TODO (5.1): Handle these in v5.1
|
||||
// TODO (6.0): Handle these in v6.0
|
||||
// "magento/*": "Magento",
|
||||
// "concrete5/*": "Concrete5",
|
||||
// "contao/*": "Contao",
|
||||
@ -58,6 +59,10 @@ struct PhpFrameworks {
|
||||
"/wp-config.php",
|
||||
"/wp-config-sample.php"
|
||||
],
|
||||
"Typo3": [
|
||||
"/typo3",
|
||||
"/public/typo3"
|
||||
]
|
||||
]
|
||||
|
||||
/**
|
||||
|