mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-08 04:20:07 +02:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
f62297ee3d | |||
2f017f6732 | |||
1c62a100af | |||
e176d6fa2d | |||
ea60626c47 | |||
69c3386088 | |||
3e898d435b | |||
a4dcd0cd3d | |||
bb382c0f74 | |||
c87c532d1c | |||
b26099369f | |||
90a8e7c336 | |||
398dad9d5e | |||
48d0878dfd | |||
4ba3415bf4 | |||
0fc7f2c905 | |||
eebfa823f1 | |||
edc23f97de | |||
7b79cb7fe8 | |||
88d81f343e | |||
8486997f01 | |||
af55e7fabc | |||
2025c951e8 | |||
a71c6afc0d |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
phpmon.xcodeproj/project.xcworkspace
|
phpmon.xcodeproj/project.xcworkspace
|
||||||
phpmon.xcodeproj/xcuserdata
|
phpmon.xcodeproj/xcuserdata
|
||||||
|
PHP Monitor.xcodeproj/project.xcworkspace
|
||||||
|
PHP Monitor.xcodeproj/xcuserdata
|
||||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 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
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -8,33 +8,40 @@
|
|||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */; };
|
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */; };
|
||||||
C41C1B3922B0097F00E7CF16 /* LogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B3822B0097F00E7CF16 /* LogViewController.swift */; };
|
|
||||||
C41C1B3B22B0098000E7CF16 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3A22B0098000E7CF16 /* Assets.xcassets */; };
|
C41C1B3B22B0098000E7CF16 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3A22B0098000E7CF16 /* Assets.xcassets */; };
|
||||||
C41C1B3E22B0098000E7CF16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3C22B0098000E7CF16 /* Main.storyboard */; };
|
C41C1B3E22B0098000E7CF16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3C22B0098000E7CF16 /* Main.storyboard */; };
|
||||||
C41C1B4722B009A400E7CF16 /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4622B009A400E7CF16 /* Shell.swift */; };
|
C41C1B4722B009A400E7CF16 /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4622B009A400E7CF16 /* Shell.swift */; };
|
||||||
C41C1B4922B00A9800E7CF16 /* ImageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4822B00A9800E7CF16 /* ImageGenerator.swift */; };
|
C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */; };
|
||||||
C41C1B4B22B019FF00E7CF16 /* PhpVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4A22B019FF00E7CF16 /* PhpVersion.swift */; };
|
C41C1B4B22B019FF00E7CF16 /* PhpVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4A22B019FF00E7CF16 /* PhpVersion.swift */; };
|
||||||
C41C1B4D22B0215A00E7CF16 /* Services.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4C22B0215A00E7CF16 /* Services.swift */; };
|
C41C1B4D22B0215A00E7CF16 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4C22B0215A00E7CF16 /* Actions.swift */; };
|
||||||
|
C42295DD2358D02000E263B2 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42295DC2358D02000E263B2 /* Command.swift */; };
|
||||||
C476FF9822B0DD830098105B /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C476FF9722B0DD830098105B /* Alert.swift */; };
|
C476FF9822B0DD830098105B /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C476FF9722B0DD830098105B /* Alert.swift */; };
|
||||||
C4D8016622B1584700C6DA1B /* BootChecks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* BootChecks.swift */; };
|
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2322D70A4700B5F6B3 /* App.swift */; };
|
||||||
|
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */; };
|
||||||
|
C4D8016622B1584700C6DA1B /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
|
||||||
C4EE188422D3386B00E126E5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE188322D3386B00E126E5 /* Constants.swift */; };
|
C4EE188422D3386B00E126E5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE188322D3386B00E126E5 /* Constants.swift */; };
|
||||||
|
C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8C0A322D4F12C002EFE61 /* DateExtension.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
C41C1B3322B0097F00E7CF16 /* phpmon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = phpmon.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
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>"; };
|
C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
C41C1B3822B0097F00E7CF16 /* LogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewController.swift; sourceTree = "<group>"; };
|
|
||||||
C41C1B3A22B0098000E7CF16 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
C41C1B3A22B0098000E7CF16 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
C41C1B3D22B0098000E7CF16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
C41C1B3D22B0098000E7CF16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
C41C1B3F22B0098000E7CF16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
C41C1B3F22B0098000E7CF16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
C41C1B4022B0098000E7CF16 /* phpmon.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = phpmon.entitlements; sourceTree = "<group>"; };
|
C41C1B4022B0098000E7CF16 /* phpmon.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = phpmon.entitlements; sourceTree = "<group>"; };
|
||||||
C41C1B4622B009A400E7CF16 /* Shell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shell.swift; sourceTree = "<group>"; };
|
C41C1B4622B009A400E7CF16 /* Shell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shell.swift; sourceTree = "<group>"; };
|
||||||
C41C1B4822B00A9800E7CF16 /* ImageGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageGenerator.swift; sourceTree = "<group>"; };
|
C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarImageGenerator.swift; sourceTree = "<group>"; };
|
||||||
C41C1B4A22B019FF00E7CF16 /* PhpVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpVersion.swift; sourceTree = "<group>"; };
|
C41C1B4A22B019FF00E7CF16 /* PhpVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpVersion.swift; sourceTree = "<group>"; };
|
||||||
C41C1B4C22B0215A00E7CF16 /* Services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Services.swift; sourceTree = "<group>"; };
|
C41C1B4C22B0215A00E7CF16 /* Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = "<group>"; };
|
||||||
|
C42295DC2358D02000E263B2 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
|
||||||
C476FF9722B0DD830098105B /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = "<group>"; };
|
C476FF9722B0DD830098105B /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = "<group>"; };
|
||||||
C4D8016522B1584700C6DA1B /* BootChecks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BootChecks.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>"; };
|
||||||
|
C4D8016522B1584700C6DA1B /* Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Startup.swift; sourceTree = "<group>"; };
|
||||||
C4EE188322D3386B00E126E5 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
C4EE188322D3386B00E126E5 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.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>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -51,6 +58,7 @@
|
|||||||
C41C1B2A22B0097F00E7CF16 = {
|
C41C1B2A22B0097F00E7CF16 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
C4F8C0A522D4FA41002EFE61 /* README.md */,
|
||||||
C41C1B3522B0097F00E7CF16 /* phpmon */,
|
C41C1B3522B0097F00E7CF16 /* phpmon */,
|
||||||
C41C1B3422B0097F00E7CF16 /* Products */,
|
C41C1B3422B0097F00E7CF16 /* Products */,
|
||||||
);
|
);
|
||||||
@ -59,7 +67,7 @@
|
|||||||
C41C1B3422B0097F00E7CF16 /* Products */ = {
|
C41C1B3422B0097F00E7CF16 /* Products */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
C41C1B3322B0097F00E7CF16 /* phpmon.app */,
|
C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -67,13 +75,12 @@
|
|||||||
C41C1B3522B0097F00E7CF16 /* phpmon */ = {
|
C41C1B3522B0097F00E7CF16 /* phpmon */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
C4EE188322D3386B00E126E5 /* Constants.swift */,
|
|
||||||
C41E181722CB61EB0072CF09 /* Classes */,
|
|
||||||
C41E181622CB61890072CF09 /* Startup */,
|
|
||||||
C41E181522CB614C0072CF09 /* Terminal */,
|
|
||||||
C41C1B4E22B024F100E7CF16 /* Helpers */,
|
|
||||||
C41E181822CB62200072CF09 /* View Controllers */,
|
|
||||||
C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */,
|
C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */,
|
||||||
|
C4EE188322D3386B00E126E5 /* Constants.swift */,
|
||||||
|
C4811D2622D70CEF00B5F6B3 /* Singletons */,
|
||||||
|
C41E181722CB61EB0072CF09 /* Classes */,
|
||||||
|
C41E181822CB62200072CF09 /* View Controllers */,
|
||||||
|
C4F8C0A222D4F100002EFE61 /* Extensions */,
|
||||||
C41C1B3F22B0098000E7CF16 /* Info.plist */,
|
C41C1B3F22B0098000E7CF16 /* Info.plist */,
|
||||||
C41C1B4022B0098000E7CF16 /* phpmon.entitlements */,
|
C41C1B4022B0098000E7CF16 /* phpmon.entitlements */,
|
||||||
C41C1B3A22B0098000E7CF16 /* Assets.xcassets */,
|
C41C1B3A22B0098000E7CF16 /* Assets.xcassets */,
|
||||||
@ -81,36 +88,11 @@
|
|||||||
path = phpmon;
|
path = phpmon;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
C41C1B4E22B024F100E7CF16 /* Helpers */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
C41C1B4822B00A9800E7CF16 /* ImageGenerator.swift */,
|
|
||||||
C476FF9722B0DD830098105B /* Alert.swift */,
|
|
||||||
);
|
|
||||||
path = Helpers;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
C41E181522CB614C0072CF09 /* Terminal */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
C41C1B4622B009A400E7CF16 /* Shell.swift */,
|
|
||||||
C41C1B4C22B0215A00E7CF16 /* Services.swift */,
|
|
||||||
);
|
|
||||||
path = Terminal;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
C41E181622CB61890072CF09 /* Startup */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
C4D8016522B1584700C6DA1B /* BootChecks.swift */,
|
|
||||||
);
|
|
||||||
path = Startup;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
C41E181722CB61EB0072CF09 /* Classes */ = {
|
C41E181722CB61EB0072CF09 /* Classes */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
C41C1B4A22B019FF00E7CF16 /* PhpVersion.swift */,
|
C4811D2722D70D8E00B5F6B3 /* Commands */,
|
||||||
|
C4811D2822D70D9C00B5F6B3 /* Helpers */,
|
||||||
);
|
);
|
||||||
path = Classes;
|
path = Classes;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -119,17 +101,54 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
C41C1B3C22B0098000E7CF16 /* Main.storyboard */,
|
C41C1B3C22B0098000E7CF16 /* Main.storyboard */,
|
||||||
C41C1B3822B0097F00E7CF16 /* LogViewController.swift */,
|
|
||||||
);
|
);
|
||||||
path = "View Controllers";
|
path = "View Controllers";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
C4811D2622D70CEF00B5F6B3 /* Singletons */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C41C1B4622B009A400E7CF16 /* Shell.swift */,
|
||||||
|
C4811D2322D70A4700B5F6B3 /* App.swift */,
|
||||||
|
C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */,
|
||||||
|
C42295DC2358D02000E263B2 /* Command.swift */,
|
||||||
|
);
|
||||||
|
path = Singletons;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
C4811D2722D70D8E00B5F6B3 /* Commands */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C41C1B4C22B0215A00E7CF16 /* Actions.swift */,
|
||||||
|
C4D8016522B1584700C6DA1B /* Startup.swift */,
|
||||||
|
);
|
||||||
|
path = Commands;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
C4811D2822D70D9C00B5F6B3 /* Helpers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C476FF9722B0DD830098105B /* Alert.swift */,
|
||||||
|
C41C1B4A22B019FF00E7CF16 /* PhpVersion.swift */,
|
||||||
|
C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */,
|
||||||
|
);
|
||||||
|
path = Helpers;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
C4F8C0A222D4F100002EFE61 /* Extensions */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C4F8C0A322D4F12C002EFE61 /* DateExtension.swift */,
|
||||||
|
);
|
||||||
|
path = Extensions;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
C41C1B3222B0097F00E7CF16 /* phpmon */ = {
|
C41C1B3222B0097F00E7CF16 /* PHP Monitor */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = C41C1B4322B0098000E7CF16 /* Build configuration list for PBXNativeTarget "phpmon" */;
|
buildConfigurationList = C41C1B4322B0098000E7CF16 /* Build configuration list for PBXNativeTarget "PHP Monitor" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
C41C1B2F22B0097F00E7CF16 /* Sources */,
|
C41C1B2F22B0097F00E7CF16 /* Sources */,
|
||||||
C41C1B3022B0097F00E7CF16 /* Frameworks */,
|
C41C1B3022B0097F00E7CF16 /* Frameworks */,
|
||||||
@ -139,9 +158,9 @@
|
|||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
name = phpmon;
|
name = "PHP Monitor";
|
||||||
productName = phpmon;
|
productName = phpmon;
|
||||||
productReference = C41C1B3322B0097F00E7CF16 /* phpmon.app */;
|
productReference = C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
/* End PBXNativeTarget section */
|
/* End PBXNativeTarget section */
|
||||||
@ -151,7 +170,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastSwiftUpdateCheck = 1020;
|
LastSwiftUpdateCheck = 1020;
|
||||||
LastUpgradeCheck = 1020;
|
LastUpgradeCheck = 1110;
|
||||||
ORGANIZATIONNAME = "Nico Verbruggen";
|
ORGANIZATIONNAME = "Nico Verbruggen";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
C41C1B3222B0097F00E7CF16 = {
|
C41C1B3222B0097F00E7CF16 = {
|
||||||
@ -159,7 +178,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = C41C1B2E22B0097F00E7CF16 /* Build configuration list for PBXProject "phpmon" */;
|
buildConfigurationList = C41C1B2E22B0097F00E7CF16 /* Build configuration list for PBXProject "PHP Monitor" */;
|
||||||
compatibilityVersion = "Xcode 9.3";
|
compatibilityVersion = "Xcode 9.3";
|
||||||
developmentRegion = en;
|
developmentRegion = en;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
@ -172,7 +191,7 @@
|
|||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
C41C1B3222B0097F00E7CF16 /* phpmon */,
|
C41C1B3222B0097F00E7CF16 /* PHP Monitor */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@ -194,11 +213,14 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
C4D8016622B1584700C6DA1B /* BootChecks.swift in Sources */,
|
C4D8016622B1584700C6DA1B /* Startup.swift in Sources */,
|
||||||
|
C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */,
|
||||||
C41C1B4722B009A400E7CF16 /* Shell.swift in Sources */,
|
C41C1B4722B009A400E7CF16 /* Shell.swift in Sources */,
|
||||||
C41C1B4D22B0215A00E7CF16 /* Services.swift in Sources */,
|
C41C1B4D22B0215A00E7CF16 /* Actions.swift in Sources */,
|
||||||
C41C1B4922B00A9800E7CF16 /* ImageGenerator.swift in Sources */,
|
C42295DD2358D02000E263B2 /* Command.swift in Sources */,
|
||||||
C41C1B3922B0097F00E7CF16 /* LogViewController.swift in Sources */,
|
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */,
|
||||||
|
C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */,
|
||||||
|
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */,
|
||||||
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */,
|
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */,
|
||||||
C41C1B4B22B019FF00E7CF16 /* PhpVersion.swift in Sources */,
|
C41C1B4B22B019FF00E7CF16 /* PhpVersion.swift in Sources */,
|
||||||
C476FF9822B0DD830098105B /* Alert.swift in Sources */,
|
C476FF9822B0DD830098105B /* Alert.swift in Sources */,
|
||||||
@ -340,14 +362,17 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = phpmon/phpmon.entitlements;
|
CODE_SIGN_ENTITLEMENTS = phpmon/phpmon.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = 16;
|
||||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||||
INFOPLIST_FILE = phpmon/Info.plist;
|
INFOPLIST_FILE = phpmon/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 1.6;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@ -359,14 +384,17 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = phpmon/phpmon.entitlements;
|
CODE_SIGN_ENTITLEMENTS = phpmon/phpmon.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = 16;
|
||||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||||
INFOPLIST_FILE = phpmon/Info.plist;
|
INFOPLIST_FILE = phpmon/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 1.6;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@ -376,7 +404,7 @@
|
|||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
C41C1B2E22B0097F00E7CF16 /* Build configuration list for PBXProject "phpmon" */ = {
|
C41C1B2E22B0097F00E7CF16 /* Build configuration list for PBXProject "PHP Monitor" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
C41C1B4122B0098000E7CF16 /* Debug */,
|
C41C1B4122B0098000E7CF16 /* Debug */,
|
||||||
@ -385,7 +413,7 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
C41C1B4322B0098000E7CF16 /* Build configuration list for PBXNativeTarget "phpmon" */ = {
|
C41C1B4322B0098000E7CF16 /* Build configuration list for PBXNativeTarget "PHP Monitor" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
C41C1B4422B0098000E7CF16 /* Debug */,
|
C41C1B4422B0098000E7CF16 /* Debug */,
|
66
README.md
66
README.md
@ -1,14 +1,38 @@
|
|||||||
# phpmon
|
# PHP Monitor
|
||||||
|
|
||||||
<img src="./docs/phpmon.png" width="306px" alt="phpmon screenshot"/>
|
PHP Monitor (or phpmon) is a macOS utility that runs on your Mac and displays the active PHP version in your status bar.
|
||||||
|
|
||||||
phpmon is a macOS utility that runs on your Mac and displays the active PHP version in your status bar. Handy if you're running multiple versions of PHP with Homebrew and wish to see which version is currently linked & active with Laravel Valet.
|
<img src="./docs/screenshot.png" width="278px" alt="phpmon screenshot"/>
|
||||||
|
|
||||||
|
For me, it comes in handy when running multiple versions of PHP with Homebrew and you wish to be able to see at a glance which version is currently linked & active with Laravel Valet, and switch between versions.
|
||||||
|
|
||||||
|
## System requirements
|
||||||
|
|
||||||
|
**Minimal system requirements**
|
||||||
|
|
||||||
|
* macOS 10.14 or higher
|
||||||
|
* PHP 7.4 installed via Homebrew
|
||||||
|
* Laravel Valet 2.3 or higher installed
|
||||||
|
|
||||||
|
**Recommended system**
|
||||||
|
|
||||||
|
* macOS 10.15 Catalina
|
||||||
|
* PHP 7.4 installed with Homebrew 2.2
|
||||||
|
- other versions of PHP are optional
|
||||||
|
- includes support for PHP 5.6 and PHP 7.0 [as well](https://github.com/eXolnet/homebrew-deprecated)
|
||||||
|
* Laravel Valet 2.5.x installed
|
||||||
|
|
||||||
|
## Why I built this
|
||||||
|
|
||||||
|
I wanted to be able to see at a glance which version of PHP was linked, and handle dealing with Laravel Valet in a simple app without having to deal with the terminal every time.
|
||||||
|
|
||||||
|
Initially, I had an Alfred workflow for this. But this does the job as well, while also showing me at all times which version of PHP is linked (which is the main benefit over e.g. an Alfred workflow).
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
### Version detection
|
### Version detection
|
||||||
|
|
||||||
This utility runs `php -r 'print phpversion();'` in the background periodically and extracts the version number.
|
This utility runs `php -r 'print phpversion();'` in the background periodically (every 60 seconds) and extracts the version number.
|
||||||
|
|
||||||
### Switching PHP versions
|
### Switching PHP versions
|
||||||
|
|
||||||
@ -16,15 +40,43 @@ This utility will detect which PHP versions you have installed via Homebrew, and
|
|||||||
|
|
||||||
This means:
|
This means:
|
||||||
|
|
||||||
- You have at least the latest version of PHP installed (`php@7.3`)
|
- You have at least the latest version of PHP installed (`php@7.4`)
|
||||||
- You have installed Laravel Valet (`which valet` returns `/usr/local/bin/valet`)
|
- You have installed Laravel Valet (`which valet` returns `/usr/local/bin/valet`)
|
||||||
- You ran `valet trust`, which means Valet commands can be run without using sudo
|
- You ran `valet trust`, which means Valet commands can be run without using sudo
|
||||||
|
|
||||||
The utility runs the following commands:
|
The utility runs the following commands:
|
||||||
|
|
||||||
- Unlink all detected PHP versions
|
- Unlink all detected PHP versions
|
||||||
- Switch to PHP 7.3 (this is done in order to ensure that Valet works, even when attempting to use PHP 5.6)
|
- Switch to PHP 7.4 (this is done in order to ensure that Valet works, even when attempting to use PHP 5.6)
|
||||||
- Tell Valet to switch to a specific PHP version
|
- Tell Valet to switch to a specific PHP version
|
||||||
- Link the desired version of PHP
|
- Link the desired version of PHP
|
||||||
|
|
||||||
If you want to know more about how this works, you can find the file Services.swift under the Helpers directory to learn more about how switching PHP versions works. In the end, this just executes some shell commands.
|
### Want to know more?
|
||||||
|
|
||||||
|
If you want to know more about how this works, I recommend you check out the source code.
|
||||||
|
|
||||||
|
This app isn't very complicated after all. In the end, this just (conveniently) executes some shell commands.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Reasons for alerts at startup
|
||||||
|
|
||||||
|
PHP Monitor performs some integrity checks to ensure a good experience when using the app. You'll get a message telling you that PHP Monitor won't work correctly in the following scenarios:
|
||||||
|
|
||||||
|
- The PHP binary is not located in `/usr/local/bin/php`
|
||||||
|
- PHP 7.4 is missing in `/usr/local/opt`
|
||||||
|
- Laravel Valet is missing in `/usr/local/bin/valet`
|
||||||
|
- Brew has not been added to sudoers in `/private/etc/sudoers.d/brew`
|
||||||
|
- Valet has not been added to sudoers in `/private/etc/sudoers.d/valet`
|
||||||
|
|
||||||
|
Follow instructions as specified in the alert in order to resolve any issues.
|
||||||
|
|
||||||
|
### Still seeing another PHP version (from before switching versions)?
|
||||||
|
|
||||||
|
If you're still seeing an old version of PHP in your scripts — e.g. when running `phpinfo()` — I recommend you shut down the PHP service by running:
|
||||||
|
|
||||||
|
sudo brew services stop php
|
||||||
|
|
||||||
|
Please note that PHP Monitor will not be able to stop this service (it doesn't run as an administrator), so you'll need to handle this yourself.
|
||||||
|
|
||||||
|
You should only have to do this **once**, and then PHP Monitor should work as usual.
|
||||||
|
BIN
docs/phpmon.png
BIN
docs/phpmon.png
Binary file not shown.
Before Width: | Height: | Size: 317 KiB |
BIN
docs/screenshot.png
Normal file
BIN
docs/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 314 KiB |
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "self:phpmon.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
// AppDelegate.swift
|
// AppDelegate.swift
|
||||||
// phpmon
|
// PHP Monitor
|
||||||
//
|
//
|
||||||
// Created by Nico Verbruggen on 11/06/2019.
|
// Created by Nico Verbruggen on 11/06/2019.
|
||||||
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
@ -13,156 +13,27 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
|
|
||||||
// MARK: - Variables
|
// MARK: - Variables
|
||||||
|
|
||||||
let statusItem = NSStatusBar.system.statusItem(withLength: 32)
|
let sharedShell : Shell
|
||||||
var timer: Timer?
|
let state : App
|
||||||
var version: PhpVersion? = nil
|
let menu : MainMenu
|
||||||
var availablePhpVersions : [String] = []
|
|
||||||
var busy: Bool = false
|
// MARK: - Initializer
|
||||||
var log: String = ""
|
|
||||||
var windowController: NSWindowController? = nil
|
override init() {
|
||||||
|
self.sharedShell = Shell.user
|
||||||
|
self.state = App.shared
|
||||||
|
self.menu = MainMenu.shared
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
|
|
||||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||||
// Start with the icon
|
self.menu.startup()
|
||||||
self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
|
||||||
// Perform environment boot checks
|
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
|
||||||
BootChecks.perform()
|
|
||||||
self.availablePhpVersions = Services.detectPhpVersions()
|
|
||||||
print("The following PHP versions were detected:")
|
|
||||||
print(self.availablePhpVersions)
|
|
||||||
self.updatePhpVersionInStatusBar()
|
|
||||||
// Schedule a request to fetch the PHP version every 15 seconds
|
|
||||||
Timer.scheduledTimer(
|
|
||||||
timeInterval: 15,
|
|
||||||
target: self,
|
|
||||||
selector: #selector(self.updatePhpVersionInStatusBar),
|
|
||||||
userInfo: nil,
|
|
||||||
repeats: true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func applicationWillTerminate(_ aNotification: Notification) {
|
func applicationWillTerminate(_ aNotification: Notification) {
|
||||||
// Insert code here to tear down your application
|
self.state.windowController = nil
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - UI related
|
|
||||||
|
|
||||||
func setStatusBarImage(version: String) {
|
|
||||||
self.setStatusBar(image: ImageGenerator.generateImageForStatusBar(width: 32.0, text: version))
|
|
||||||
}
|
|
||||||
|
|
||||||
func setStatusBar(image: NSImage) {
|
|
||||||
if let button = statusItem.button {
|
|
||||||
image.isTemplate = true
|
|
||||||
button.image = image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateMenu() {
|
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
|
||||||
let menu = NSMenu()
|
|
||||||
var string = "We are not sure what version of PHP you are running."
|
|
||||||
if (self.version != nil) {
|
|
||||||
string = "You are running PHP \(self.version!.long)"
|
|
||||||
}
|
|
||||||
menu.addItem(NSMenuItem(title: string, action: nil, keyEquivalent: ""))
|
|
||||||
if (self.version != nil) {
|
|
||||||
// Actions
|
|
||||||
menu.addItem(NSMenuItem.separator())
|
|
||||||
menu.addItem(NSMenuItem(title: "Open php.ini in Finder", action: #selector(self.openActiveConfigFolder), keyEquivalent: ""))
|
|
||||||
// OPTIONAL
|
|
||||||
// menu.addItem(NSMenuItem(title: "Restart PHP \(self.version!.short) service", action: #selector(self.restartPhp), keyEquivalent: ""))
|
|
||||||
}
|
|
||||||
menu.addItem(NSMenuItem.separator())
|
|
||||||
if (self.availablePhpVersions.count > 0 && !self.busy) {
|
|
||||||
var shortcutKey = 1
|
|
||||||
for index in (0..<self.availablePhpVersions.count).reversed() {
|
|
||||||
let version = self.availablePhpVersions[index]
|
|
||||||
let action = #selector(self.switchToPhpVersion(sender:))
|
|
||||||
let menuItem = NSMenuItem(title: "Switch to PHP \(version)", action: (version == self.version?.short) ? nil : action, keyEquivalent: "\(shortcutKey)")
|
|
||||||
menuItem.tag = index
|
|
||||||
shortcutKey = shortcutKey + 1
|
|
||||||
menu.addItem(menuItem)
|
|
||||||
}
|
|
||||||
menu.addItem(NSMenuItem.separator())
|
|
||||||
}
|
|
||||||
if (self.busy) {
|
|
||||||
menu.addItem(NSMenuItem(title: "Switching PHP versions...", action: nil, keyEquivalent: ""))
|
|
||||||
menu.addItem(NSMenuItem.separator())
|
|
||||||
}
|
|
||||||
// TODO: Enable when implementation is complete
|
|
||||||
// menu.addItem(NSMenuItem(title: "View terminal output", action: #selector(self.openOutput), keyEquivalent: ""))
|
|
||||||
menu.addItem(NSMenuItem(title: "About phpmon", action: #selector(self.openAbout), keyEquivalent: ""))
|
|
||||||
menu.addItem(NSMenuItem(title: "Quit phpmon", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.statusItem.menu = menu
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Callable via Obj-C (#selector)
|
|
||||||
|
|
||||||
@objc func openOutput() {
|
|
||||||
if (self.windowController == nil) {
|
|
||||||
let vc = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "logWindow") as! LogViewController
|
|
||||||
let window = NSWindow(contentViewController: vc)
|
|
||||||
window.title = "Terminal Output"
|
|
||||||
self.windowController = NSWindowController(window: window)
|
|
||||||
}
|
|
||||||
self.windowController!.showWindow(self)
|
|
||||||
// TODO: Send window to front (if possible)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func updatePhpVersionInStatusBar() {
|
|
||||||
self.version = PhpVersion()
|
|
||||||
if (self.busy) {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.setStatusBarImage(version: self.version!.short)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.updateMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func openAbout() {
|
|
||||||
NSApplication.shared.activate(ignoringOtherApps: true)
|
|
||||||
NSApplication.shared.orderFrontStandardAboutPanel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func openActiveConfigFolder() {
|
|
||||||
Services.openPhpConfigFolder(version: self.version!.short)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func restartPhp() {
|
|
||||||
Services.restartPhp(version: self.version!.short)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func switchToPhpVersion(sender: AnyObject) {
|
|
||||||
self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
|
||||||
let index = sender.tag!
|
|
||||||
let version = self.availablePhpVersions[index]
|
|
||||||
self.busy = true
|
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
|
||||||
// Update the PHP version in the status bar
|
|
||||||
self.updatePhpVersionInStatusBar()
|
|
||||||
// Update the menu
|
|
||||||
self.updateMenu()
|
|
||||||
// Switch the PHP version
|
|
||||||
Services.switchToPhpVersion(version: version, availableVersions: self.availablePhpVersions)
|
|
||||||
// Mark as no longer busy
|
|
||||||
self.busy = false
|
|
||||||
// Perform UI updates on main thread
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.updatePhpVersionInStatusBar()
|
|
||||||
self.updateMenu()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
76
phpmon/Classes/Commands/Actions.swift
Normal file
76
phpmon/Classes/Commands/Actions.swift
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
//
|
||||||
|
// Services.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 11/06/2019.
|
||||||
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import AppKit
|
||||||
|
|
||||||
|
class Actions {
|
||||||
|
|
||||||
|
public static func detectPhpVersions() -> [String] {
|
||||||
|
let files = Shell.user.pipe("ls /usr/local/opt | grep php@")
|
||||||
|
var versions = files.components(separatedBy: "\n")
|
||||||
|
// Remove all empty strings
|
||||||
|
versions.removeAll { (string) -> Bool in
|
||||||
|
return (string == "")
|
||||||
|
}
|
||||||
|
// Get a list of versions only
|
||||||
|
var versionsOnly : [String] = []
|
||||||
|
versions.forEach { (string) in
|
||||||
|
versionsOnly.append(string.components(separatedBy: "php@")[1])
|
||||||
|
}
|
||||||
|
return versionsOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func switchToPhpVersion(version: String, availableVersions: [String]) {
|
||||||
|
availableVersions.forEach { (version) in
|
||||||
|
Shell.user.run("brew unlink php@\(version)")
|
||||||
|
}
|
||||||
|
if (availableVersions.contains("7.4")) {
|
||||||
|
Shell.user.run("brew link php@7.4")
|
||||||
|
if (version == Constants.LatestPhpVersion) {
|
||||||
|
Shell.user.run("valet use php")
|
||||||
|
} else {
|
||||||
|
Shell.user.run("valet use php@\(version)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func openPhpConfigFolder(version: String) {
|
||||||
|
let files = [NSURL(fileURLWithPath: "/usr/local/etc/php/\(version)/php.ini")];
|
||||||
|
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func XdebugFound(_ version: String) -> Bool {
|
||||||
|
let command = """
|
||||||
|
grep -q 'zend_extension="xdebug.so"' /usr/local/etc/php/\(version)/php.ini; [ $? -eq 0 ] && echo "YES" || echo "NO"
|
||||||
|
"""
|
||||||
|
let output = Shell.user.pipe(command).trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
return (output == "YES")
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func XdebugEnabled(_ version: String) -> Bool {
|
||||||
|
let command = """
|
||||||
|
grep -q '; zend_extension="xdebug.so"' /usr/local/etc/php/\(version)/php.ini; [ $? -eq 0 ] && echo "YES" || echo "NO"
|
||||||
|
"""
|
||||||
|
let output = Shell.user.pipe(command).trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
return (output == "NO")
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func toggleXdebug() {
|
||||||
|
let version = App.shared.currentVersion?.short
|
||||||
|
var command = """
|
||||||
|
sed -i '' 's/; zend_extension="xdebug.so"/zend_extension="xdebug.so"/g' /usr/local/etc/php/\(version!)/php.ini
|
||||||
|
"""
|
||||||
|
if (self.XdebugEnabled(version!)) {
|
||||||
|
command = """
|
||||||
|
sed -i '' 's/zend_extension="xdebug.so"/; zend_extension="xdebug.so"/g' /usr/local/etc/php/\(version!)/php.ini
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
Shell.user.run(command)
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
// Environment.swift
|
// Environment.swift
|
||||||
// phpmon
|
// PHP Monitor
|
||||||
//
|
//
|
||||||
// Created by Nico Verbruggen on 12/06/2019.
|
// Created by Nico Verbruggen on 12/06/2019.
|
||||||
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
@ -8,36 +8,36 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class BootChecks {
|
class Startup {
|
||||||
|
|
||||||
public static func perform()
|
public static func checkEnvironment()
|
||||||
{
|
{
|
||||||
self.presentAlertOnMainThreadIf(
|
self.presentAlertOnMainThreadIf(
|
||||||
!Shell.execute(command: "which php").contains("/usr/local/bin/php"),
|
!Shell.user.pipe("which php").contains("/usr/local/bin/php"),
|
||||||
messageText: "PHP is not correctly installed",
|
messageText: "PHP is not correctly installed",
|
||||||
informativeText: "You must install PHP via brew. Try running `which php` in Terminal, it should return `/usr/local/bin/php`. The app will not work correctly until you resolve this issue."
|
informativeText: "You must install PHP via brew. Try running `which php` in Terminal, it should return `/usr/local/bin/php`. The app will not work correctly until you resolve this issue."
|
||||||
)
|
)
|
||||||
|
|
||||||
self.presentAlertOnMainThreadIf(
|
self.presentAlertOnMainThreadIf(
|
||||||
!Shell.execute(command: "ls /usr/local/opt | grep php@7.3").contains("php@7.3"),
|
!Shell.user.pipe("ls /usr/local/opt | grep php@7.4").contains("php@7.4"),
|
||||||
messageText: "PHP 7.3 is not correctly installed",
|
messageText: "PHP 7.4 is not correctly installed",
|
||||||
informativeText: "PHP 7.3 alias was not found in `/usr/local/opt`. The app will not work correctly until you resolve this issue."
|
informativeText: "PHP 7.4 alias was not found in `/usr/local/opt`. The app will not work correctly until you resolve this issue."
|
||||||
)
|
)
|
||||||
|
|
||||||
self.presentAlertOnMainThreadIf(
|
self.presentAlertOnMainThreadIf(
|
||||||
!Shell.execute(command: "which valet").contains("/usr/local/bin/valet"),
|
!Shell.user.pipe("which valet").contains("/usr/local/bin/valet"),
|
||||||
messageText: "Laravel Valet is not correctly installed",
|
messageText: "Laravel Valet is not correctly installed",
|
||||||
informativeText: "You must install Valet via brew. Try running `which valet` in Terminal, it should return `/usr/local/bin/valet`. The app will not work correctly until you resolve this issue."
|
informativeText: "You must install Valet via brew. Try running `which valet` in Terminal, it should return `/usr/local/bin/valet`. The app will not work correctly until you resolve this issue."
|
||||||
)
|
)
|
||||||
|
|
||||||
self.presentAlertOnMainThreadIf(
|
self.presentAlertOnMainThreadIf(
|
||||||
!Shell.execute(command: "cat /private/etc/sudoers.d/brew").contains("/usr/local/bin/brew"),
|
!Shell.user.pipe("cat /private/etc/sudoers.d/brew").contains("/usr/local/bin/brew"),
|
||||||
messageText: "Brew has not been added to sudoers.d",
|
messageText: "Brew has not been added to sudoers.d",
|
||||||
informativeText: "You must run `sudo valet trust` to ensure Valet can start and stop services without having to use sudo every time. The app will not work correctly until you resolve this issue."
|
informativeText: "You must run `sudo valet trust` to ensure Valet can start and stop services without having to use sudo every time. The app will not work correctly until you resolve this issue."
|
||||||
)
|
)
|
||||||
|
|
||||||
self.presentAlertOnMainThreadIf(
|
self.presentAlertOnMainThreadIf(
|
||||||
!Shell.execute(command: "cat /private/etc/sudoers.d/valet").contains("/usr/local/bin/valet"),
|
!Shell.user.pipe("cat /private/etc/sudoers.d/valet").contains("/usr/local/bin/valet"),
|
||||||
messageText: "Valet has not been added to sudoers.d",
|
messageText: "Valet has not been added to sudoers.d",
|
||||||
informativeText: "You must run `sudo valet trust` to ensure Valet can start and stop services without having to use sudo every time. The app will not work correctly until you resolve this issue."
|
informativeText: "You must run `sudo valet trust` to ensure Valet can start and stop services without having to use sudo every time. The app will not work correctly until you resolve this issue."
|
||||||
)
|
)
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
// Alert.swift
|
// Alert.swift
|
||||||
// phpmon
|
// PHP Monitor
|
||||||
//
|
//
|
||||||
// Created by Nico Verbruggen on 12/06/2019.
|
// Created by Nico Verbruggen on 12/06/2019.
|
||||||
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
// ImageGenerator.swift
|
// ImageGenerator.swift
|
||||||
// phpmon
|
// PHP Monitor
|
||||||
//
|
//
|
||||||
// Created by Nico Verbruggen on 11/06/2019.
|
// Created by Nico Verbruggen on 11/06/2019.
|
||||||
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
@ -8,14 +8,15 @@
|
|||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class ImageGenerator {
|
class MenuBarImageGenerator {
|
||||||
|
|
||||||
public static func generateImageForStatusBar(width: CGFloat = 30.0, height: CGFloat = 20.0, text: String) -> NSImage {
|
/**
|
||||||
let image = NSImage(size: NSMakeSize(width, height))
|
Takes a string and converts it to an image that can be displayed in the menu bar.
|
||||||
let font = NSFont.systemFont(ofSize: 14)
|
The width of the NSImage depends on the length of the text.
|
||||||
|
*/
|
||||||
|
public static func textToImage(text: String) -> NSImage {
|
||||||
|
|
||||||
let imageRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
|
let font = NSFont.systemFont(ofSize: 14, weight: .medium)
|
||||||
let textRect = CGRect(x: 5, y: -1, width: image.size.width, height: image.size.height)
|
|
||||||
|
|
||||||
let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
|
let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
|
||||||
let textFontAttributes = [
|
let textFontAttributes = [
|
||||||
@ -24,8 +25,23 @@ class ImageGenerator {
|
|||||||
NSAttributedString.Key.paragraphStyle: textStyle
|
NSAttributedString.Key.paragraphStyle: textStyle
|
||||||
]
|
]
|
||||||
|
|
||||||
let targetImage: NSImage = NSImage(size: image.size)
|
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)
|
||||||
|
let textSize = attributedString.size()
|
||||||
|
|
||||||
|
// Add padding to the width of the menu bar item
|
||||||
|
let size = NSSize(width: textSize.width + (2 * padding), height: textSize.height)
|
||||||
|
let image = NSImage(size: size)
|
||||||
|
|
||||||
|
// Set the image rect with the appropriate dimensions
|
||||||
|
let imageRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
|
||||||
|
|
||||||
|
// Position the text inside the image rect
|
||||||
|
let textRect = CGRect(x: padding, y: 0.5, width: image.size.width, height: image.size.height)
|
||||||
|
|
||||||
|
let targetImage: NSImage = NSImage(size: image.size)
|
||||||
let rep: NSBitmapImageRep = NSBitmapImageRep(
|
let rep: NSBitmapImageRep = NSBitmapImageRep(
|
||||||
bitmapDataPlanes: nil,
|
bitmapDataPlanes: nil,
|
||||||
pixelsWide: Int(image.size.width),
|
pixelsWide: Int(image.size.width),
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
// PhpVersionExtractor.swift
|
// PhpVersionExtractor.swift
|
||||||
// phpmon
|
// PHP Monitor
|
||||||
//
|
//
|
||||||
// Created by Nico Verbruggen on 11/06/2019.
|
// Created by Nico Verbruggen on 11/06/2019.
|
||||||
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
@ -13,19 +13,25 @@ class PhpVersion {
|
|||||||
var short : String = "???"
|
var short : String = "???"
|
||||||
var long : String = "???"
|
var long : String = "???"
|
||||||
|
|
||||||
|
var xdebugFound: Bool = false
|
||||||
|
var xdebugEnabled : Bool = false
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let version = Shell
|
let version = Command.execute(path: "/usr/local/bin/php", arguments: ["-r", "print phpversion();"])
|
||||||
// Get the version directly from PHP
|
|
||||||
.execute(command: "php -r 'print phpversion();'")
|
|
||||||
// also remove any colors
|
|
||||||
.replacingOccurrences(of: "\u{1b}(B\u{1b}[m", with: "")
|
|
||||||
|
|
||||||
// That's the long version
|
// That's the long version
|
||||||
self.long = version
|
self.long = version
|
||||||
|
|
||||||
// Next up, let's strip away the minor version number
|
// Next up, let's strip away the minor version number
|
||||||
let segments = long.components(separatedBy: ".")
|
let segments = long.components(separatedBy: ".")
|
||||||
|
|
||||||
// Get the first two elements
|
// Get the first two elements
|
||||||
self.short = segments[0...1].joined(separator: ".")
|
self.short = segments[0...1].joined(separator: ".")
|
||||||
|
|
||||||
|
// Load xdebug support
|
||||||
|
self.xdebugFound = Actions.XdebugFound(self.short)
|
||||||
|
if (self.xdebugFound) {
|
||||||
|
self.xdebugEnabled = Actions.XdebugEnabled(self.short)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
// Constants.swift
|
// Constants.swift
|
||||||
// phpmon
|
// PHP Monitor
|
||||||
//
|
//
|
||||||
// Created by Nico Verbruggen on 08/07/2019.
|
// Created by Nico Verbruggen on 08/07/2019.
|
||||||
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
@ -14,13 +14,13 @@ class Constants {
|
|||||||
* The PHP versions supported by this application.
|
* The PHP versions supported by this application.
|
||||||
*/
|
*/
|
||||||
static let SupportedPhpVersions = [
|
static let SupportedPhpVersions = [
|
||||||
"5.6", "7.0", "7.1", "7.2", "7.3"
|
"5.6", "7.0", "7.1", "7.2", "7.3", "7.4"
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Which php version is aliased as `php` to brew?
|
Which php version is aliased as `php` to brew?
|
||||||
This is usually the latest PHP version.
|
This is usually the latest PHP version.
|
||||||
*/
|
*/
|
||||||
static let LatestPhpVersion = "7.3"
|
static let LatestPhpVersion = "7.4"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
19
phpmon/Extensions/DateExtension.swift
Normal file
19
phpmon/Extensions/DateExtension.swift
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Date.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 09/07/2019.
|
||||||
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
extension Date
|
||||||
|
{
|
||||||
|
func toString() -> String
|
||||||
|
{
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
|
||||||
|
return dateFormatter.string(from: self)
|
||||||
|
}
|
||||||
|
}
|
@ -17,9 +17,9 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.2</string>
|
<string>$(MARKETING_VERSION)</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>10</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.utilities</string>
|
<string>public.app-category.utilities</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
40
phpmon/Singletons/App.swift
Normal file
40
phpmon/Singletons/App.swift
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// StateManager.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 11/07/2019.
|
||||||
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class App {
|
||||||
|
|
||||||
|
static let shared = App()
|
||||||
|
|
||||||
|
/**
|
||||||
|
Whether the application is busy switching versions.
|
||||||
|
*/
|
||||||
|
var busy: Bool = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
The currently active version of PHP.
|
||||||
|
*/
|
||||||
|
var currentVersion: PhpVersion? = nil
|
||||||
|
|
||||||
|
/**
|
||||||
|
All available versions of PHP.
|
||||||
|
*/
|
||||||
|
var availablePhpVersions : [String] = []
|
||||||
|
|
||||||
|
/**
|
||||||
|
The timer that will periodically fetch the PHP version that is currently active.
|
||||||
|
*/
|
||||||
|
var timer: Timer?
|
||||||
|
|
||||||
|
/**
|
||||||
|
The window controller that will show the log.
|
||||||
|
*/
|
||||||
|
var windowController: NSWindowController? = nil
|
||||||
|
|
||||||
|
}
|
50
phpmon/Singletons/Command.swift
Normal file
50
phpmon/Singletons/Command.swift
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Command.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 17/10/2019.
|
||||||
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class Command {
|
||||||
|
|
||||||
|
public static func execute(path: String, arguments: [String]) -> String {
|
||||||
|
let task = Process()
|
||||||
|
task.launchPath = path
|
||||||
|
task.arguments = arguments
|
||||||
|
|
||||||
|
let pipe = Pipe()
|
||||||
|
task.standardOutput = pipe
|
||||||
|
task.launch()
|
||||||
|
|
||||||
|
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
|
let output: String = String.init(data: data, encoding: String.Encoding.utf8)!
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func experiment() {
|
||||||
|
/*
|
||||||
|
print("Running '/usr/local/bin/php -v' directly...")
|
||||||
|
print("========================================")
|
||||||
|
var start = DispatchTime.now()
|
||||||
|
print(Command.execute(path: "/usr/local/bin/php", arguments: ["-v"]))
|
||||||
|
var end = DispatchTime.now()
|
||||||
|
var nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
|
||||||
|
var timeInterval = Double(nanoTime) / 1_000_000_000
|
||||||
|
print("Time to run command directly: \(timeInterval) seconds")
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("Running 'bash -> php -v'...")
|
||||||
|
print("========================================")
|
||||||
|
start = DispatchTime.now()
|
||||||
|
print(Shell.user.pipe("php -v"))
|
||||||
|
end = DispatchTime.now()
|
||||||
|
nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
|
||||||
|
timeInterval = Double(nanoTime) / 1_000_000_000
|
||||||
|
print("Time to run command via bash: \(timeInterval) seconds")
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
181
phpmon/Singletons/MainMenu.swift
Normal file
181
phpmon/Singletons/MainMenu.swift
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
//
|
||||||
|
// MainMenu.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 11/07/2019.
|
||||||
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class MainMenu: NSObject, NSWindowDelegate {
|
||||||
|
|
||||||
|
static let shared = MainMenu()
|
||||||
|
|
||||||
|
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||||
|
|
||||||
|
// MARK: - UI related
|
||||||
|
|
||||||
|
public func startup() {
|
||||||
|
// Start with the icon
|
||||||
|
self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
||||||
|
// Perform environment boot checks
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
|
Startup.checkEnvironment()
|
||||||
|
App.shared.availablePhpVersions = Actions.detectPhpVersions()
|
||||||
|
self.updatePhpVersionInStatusBar()
|
||||||
|
// Schedule a request to fetch the PHP version every 60 seconds
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
App.shared.timer = Timer.scheduledTimer(
|
||||||
|
timeInterval: 60,
|
||||||
|
target: self,
|
||||||
|
selector: #selector(self.updatePhpVersionInStatusBar),
|
||||||
|
userInfo: nil,
|
||||||
|
repeats: true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func update() {
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
|
let menu = NSMenu()
|
||||||
|
var string = "We are not sure what version of PHP you are running."
|
||||||
|
if (App.shared.currentVersion != nil) {
|
||||||
|
string = "You are running PHP \(App.shared.currentVersion!.long)"
|
||||||
|
}
|
||||||
|
menu.addItem(NSMenuItem(title: string, action: nil, keyEquivalent: ""))
|
||||||
|
menu.addItem(NSMenuItem.separator())
|
||||||
|
if (App.shared.availablePhpVersions.count > 0 && !App.shared.busy) {
|
||||||
|
var shortcutKey = 1
|
||||||
|
for index in (0..<App.shared.availablePhpVersions.count).reversed() {
|
||||||
|
let version = App.shared.availablePhpVersions[index]
|
||||||
|
let action = #selector(self.switchToPhpVersion(sender:))
|
||||||
|
let menuItem = NSMenuItem(title: "Switch to PHP \(version)", action: (version == App.shared.currentVersion?.short) ? nil : action, keyEquivalent: "\(shortcutKey)")
|
||||||
|
menuItem.tag = index
|
||||||
|
shortcutKey = shortcutKey + 1
|
||||||
|
menu.addItem(menuItem)
|
||||||
|
}
|
||||||
|
menu.addItem(NSMenuItem.separator())
|
||||||
|
}
|
||||||
|
if (App.shared.busy) {
|
||||||
|
menu.addItem(NSMenuItem(title: "Switching PHP versions...", action: nil, keyEquivalent: ""))
|
||||||
|
menu.addItem(NSMenuItem.separator())
|
||||||
|
}
|
||||||
|
if (App.shared.currentVersion != nil) {
|
||||||
|
menu.addItem(NSMenuItem(title: "PHP configuration file (php.ini)", action: #selector(self.openActiveConfigFolder), keyEquivalent: "c"))
|
||||||
|
let xdebugFound = App.shared.currentVersion!.xdebugFound
|
||||||
|
if (xdebugFound) {
|
||||||
|
let xdebugOn = App.shared.currentVersion!.xdebugEnabled
|
||||||
|
let xdebugToggleMenuItem = NSMenuItem(
|
||||||
|
title: "Xdebug",
|
||||||
|
action: #selector(self.toggleXdebug), keyEquivalent: "x"
|
||||||
|
)
|
||||||
|
if (xdebugOn) {
|
||||||
|
xdebugToggleMenuItem.state = .on
|
||||||
|
}
|
||||||
|
menu.addItem(xdebugToggleMenuItem)
|
||||||
|
} else {
|
||||||
|
let disabledItem = NSMenuItem(
|
||||||
|
title: "xdebug.so missing",
|
||||||
|
action: nil, keyEquivalent: "x"
|
||||||
|
)
|
||||||
|
disabledItem.isEnabled = false
|
||||||
|
menu.addItem(disabledItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu.addItem(NSMenuItem.separator())
|
||||||
|
menu.addItem(NSMenuItem(title: "About PHP Monitor", action: #selector(self.openAbout), keyEquivalent: ""))
|
||||||
|
menu.items.forEach({ (item) in
|
||||||
|
item.target = self
|
||||||
|
})
|
||||||
|
menu.addItem(NSMenuItem(title: "Quit PHP Monitor", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.statusItem.menu = menu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setStatusBarImage(version: String) {
|
||||||
|
self.setStatusBar(
|
||||||
|
image: MenuBarImageGenerator.textToImage(
|
||||||
|
text: version
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setStatusBar(image: NSImage) {
|
||||||
|
if let button = statusItem.button {
|
||||||
|
image.isTemplate = true
|
||||||
|
button.image = image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Callable via Obj-C (#selector)
|
||||||
|
|
||||||
|
@objc func updatePhpVersionInStatusBar() {
|
||||||
|
App.shared.currentVersion = PhpVersion()
|
||||||
|
if (App.shared.busy) {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.setStatusBarImage(version: App.shared.currentVersion!.short)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func openAbout() {
|
||||||
|
NSApplication.shared.activate(ignoringOtherApps: true)
|
||||||
|
NSApplication.shared.orderFrontStandardAboutPanel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func openActiveConfigFolder() {
|
||||||
|
Actions.openPhpConfigFolder(version: App.shared.currentVersion!.short)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func switchToPhpVersion(sender: AnyObject) {
|
||||||
|
self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
||||||
|
let index = sender.tag!
|
||||||
|
let version = App.shared.availablePhpVersions[index]
|
||||||
|
App.shared.busy = true
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
|
// Update the PHP version in the status bar
|
||||||
|
self.updatePhpVersionInStatusBar()
|
||||||
|
// Update the menu
|
||||||
|
self.update()
|
||||||
|
// Switch the PHP version
|
||||||
|
Actions.switchToPhpVersion(
|
||||||
|
version: version,
|
||||||
|
availableVersions: App.shared.availablePhpVersions
|
||||||
|
)
|
||||||
|
// Mark as no longer busy
|
||||||
|
App.shared.busy = false
|
||||||
|
// Perform UI updates on main thread
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.updatePhpVersionInStatusBar()
|
||||||
|
self.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func toggleXdebug() {
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
||||||
|
}
|
||||||
|
Actions.toggleXdebug()
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.updatePhpVersionInStatusBar()
|
||||||
|
self.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func windowWillClose(_ notification: Notification) {
|
||||||
|
App.shared.windowController = nil
|
||||||
|
Shell.user.delegate = nil
|
||||||
|
}
|
||||||
|
}
|
74
phpmon/Singletons/Shell.swift
Normal file
74
phpmon/Singletons/Shell.swift
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// Shell.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 11/06/2019.
|
||||||
|
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
protocol ShellDelegate: class {
|
||||||
|
func didCompleteCommand(historyItem: ShellHistoryItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShellHistoryItem {
|
||||||
|
var command: String
|
||||||
|
var output: String
|
||||||
|
var date: Date
|
||||||
|
|
||||||
|
init(command: String, output: String) {
|
||||||
|
self.command = command
|
||||||
|
self.output = output
|
||||||
|
self.date = Date()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Shell {
|
||||||
|
|
||||||
|
// Singleton to access a user shell (with --login)
|
||||||
|
static let user = Shell()
|
||||||
|
|
||||||
|
var history : [ShellHistoryItem] = []
|
||||||
|
|
||||||
|
var delegate : ShellDelegate?
|
||||||
|
|
||||||
|
/// Runs a shell command without using the description.
|
||||||
|
public func run(_ command: String) {
|
||||||
|
// Equivalent of piping to /dev/null; don't do anything with the string
|
||||||
|
_ = self.pipe(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs a shell command and returns the output.
|
||||||
|
public func pipe(_ command: String) -> String {
|
||||||
|
let task = Process()
|
||||||
|
task.launchPath = "/bin/bash"
|
||||||
|
task.arguments = ["--login", "-c", command]
|
||||||
|
|
||||||
|
let pipe = Pipe()
|
||||||
|
task.standardOutput = pipe
|
||||||
|
task.launch()
|
||||||
|
|
||||||
|
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
|
|
||||||
|
let output: String = NSString(
|
||||||
|
data: data,
|
||||||
|
encoding: String.Encoding.utf8.rawValue
|
||||||
|
)!.replacingOccurrences(
|
||||||
|
of: "\u{1B}(B\u{1B}[m",
|
||||||
|
with: ""
|
||||||
|
) as String
|
||||||
|
|
||||||
|
let historyItem = ShellHistoryItem(command: command, output: output)
|
||||||
|
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
|
self.history.append(historyItem)
|
||||||
|
// Keep the last 100 items
|
||||||
|
self.history = self.history.suffix(100)
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate?.didCompleteCommand(historyItem: historyItem)
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
}
|
@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// Services.swift
|
|
||||||
// phpmon
|
|
||||||
//
|
|
||||||
// Created by Nico Verbruggen on 11/06/2019.
|
|
||||||
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import AppKit
|
|
||||||
|
|
||||||
class Services {
|
|
||||||
public static func mysqlIsRunning() -> Bool {
|
|
||||||
let running = Shell.execute(command: "launchctl list | grep homebrew.mxcl.mysql")
|
|
||||||
return (running != "")
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func nginxIsRunning() -> Bool {
|
|
||||||
let running = Shell.execute(command: "launchctl list | grep homebrew.mxcl.nginx")
|
|
||||||
return (running != "")
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func detectPhpVersions() -> [String] {
|
|
||||||
let files = Shell.execute(command: "ls /usr/local/opt | grep php@")
|
|
||||||
var versions = files.components(separatedBy: "\n")
|
|
||||||
// Remove all empty strings
|
|
||||||
versions.removeAll { (string) -> Bool in
|
|
||||||
return (string == "")
|
|
||||||
}
|
|
||||||
// Get a list of versions only
|
|
||||||
var versionsOnly : [String] = []
|
|
||||||
versions.forEach { (string) in
|
|
||||||
versionsOnly.append(string.components(separatedBy: "php@")[1])
|
|
||||||
}
|
|
||||||
return versionsOnly
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func switchToPhpVersion(version: String, availableVersions: [String]) {
|
|
||||||
availableVersions.forEach { (version) in
|
|
||||||
_ = Shell.execute(command: "brew unlink php@\(version)")
|
|
||||||
}
|
|
||||||
if (availableVersions.contains("7.3")) {
|
|
||||||
_ = Shell.execute(command: "brew link php@7.3")
|
|
||||||
if (version == Constants.LatestPhpVersion) {
|
|
||||||
_ = Shell.execute(command: "valet use php")
|
|
||||||
} else {
|
|
||||||
_ = Shell.execute(command: "valet use php@\(version)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func restartPhp(version: String) {
|
|
||||||
_ = Shell.execute(command: "brew services restart php@\(version)")
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func openPhpConfigFolder(version: String) {
|
|
||||||
let files = [NSURL(fileURLWithPath: "/usr/local/etc/php/\(version)/php.ini")];
|
|
||||||
NSWorkspace.shared.activateFileViewerSelecting(files as [URL]);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
//
|
|
||||||
// Shell.swift
|
|
||||||
// phpmon
|
|
||||||
//
|
|
||||||
// Created by Nico Verbruggen on 11/06/2019.
|
|
||||||
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Cocoa
|
|
||||||
|
|
||||||
class Shell {
|
|
||||||
|
|
||||||
public static func execute(command: String) -> String {
|
|
||||||
let task = Process()
|
|
||||||
task.launchPath = "/bin/bash"
|
|
||||||
task.arguments = ["--login", "-c", command]
|
|
||||||
|
|
||||||
let pipe = Pipe()
|
|
||||||
task.standardOutput = pipe
|
|
||||||
task.launch()
|
|
||||||
|
|
||||||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
|
||||||
|
|
||||||
let output: String = NSString(
|
|
||||||
data: data,
|
|
||||||
encoding: String.Encoding.utf8.rawValue
|
|
||||||
)! as String
|
|
||||||
|
|
||||||
return output
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
<deployment identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15702"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
@ -11,18 +12,18 @@
|
|||||||
<application id="hnw-xV-0zn" sceneMemberID="viewController">
|
<application id="hnw-xV-0zn" sceneMemberID="viewController">
|
||||||
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="phpmon" id="1Xt-HY-uBw">
|
<menuItem title="PHP Monitor" id="1Xt-HY-uBw">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="phpmon" systemMenu="apple" id="uQy-DD-JDr">
|
<menu key="submenu" title="PHP Monitor" systemMenu="apple" id="uQy-DD-JDr">
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="About phpmon" id="5kV-Vb-QxS">
|
<menuItem title="About PHP Monitor" id="5kV-Vb-QxS">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
|
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||||
<menuItem title="Quit phpmon" keyEquivalent="q" id="4sb-4s-VLi">
|
<menuItem title="Quit PHP Monitor" keyEquivalent="q" id="4sb-4s-VLi">
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
|
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
|
||||||
</connections>
|
</connections>
|
||||||
@ -34,7 +35,7 @@
|
|||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="phpmon Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
<menuItem title="PHP Monitor Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
|
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
|
||||||
</connections>
|
</connections>
|
||||||
@ -48,22 +49,22 @@
|
|||||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
|
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
|
||||||
</connections>
|
</connections>
|
||||||
</application>
|
</application>
|
||||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="phpmon" customModuleProvider="target"/>
|
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="PHP_Monitor" customModuleProvider="target"/>
|
||||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||||
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="134" y="40"/>
|
<point key="canvasLocation" x="-343" y="-16"/>
|
||||||
</scene>
|
</scene>
|
||||||
<!--Log View Controller-->
|
<!--Log View Controller-->
|
||||||
<scene sceneID="hIz-AP-VOD">
|
<scene sceneID="hIz-AP-VOD">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController storyboardIdentifier="logWindow" id="XfG-lQ-9wD" customClass="LogViewController" customModule="phpmon" customModuleProvider="target" sceneMemberID="viewController">
|
<viewController storyboardIdentifier="logWindow" id="XfG-lQ-9wD" customClass="LogViewController" customModule="PHP_Monitor" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
<view key="view" identifier="main" id="m2S-Jp-Qdl">
|
<view key="view" identifier="main" id="m2S-Jp-Qdl">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="578" height="308"/>
|
<rect key="frame" x="0.0" y="0.0" width="662" height="475"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ICa-gx-jgq">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ICa-gx-jgq">
|
||||||
<rect key="frame" x="489" y="13" width="75" height="32"/>
|
<rect key="frame" x="578" y="8" width="75" height="32"/>
|
||||||
<buttonCell key="cell" type="push" title="Close" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="3md-FI-EWa">
|
<buttonCell key="cell" type="push" title="Close" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="3md-FI-EWa">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
@ -73,45 +74,49 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<scrollView borderType="line" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vZy-5S-021">
|
<scrollView borderType="line" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vZy-5S-021">
|
||||||
<rect key="frame" x="20" y="51" width="538" height="237"/>
|
<rect key="frame" x="15" y="46" width="632" height="414"/>
|
||||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="s5L-AU-0fw">
|
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="s5L-AU-0fw">
|
||||||
<rect key="frame" x="1" y="1" width="536" height="235"/>
|
<rect key="frame" x="1" y="1" width="630" height="412"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textView importsGraphics="NO" richText="NO" verticallyResizable="YES" smartInsertDelete="YES" id="tN6-Y9-1pA">
|
<textView importsGraphics="NO" richText="NO" verticallyResizable="YES" smartInsertDelete="YES" id="tN6-Y9-1pA">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="536" height="235"/>
|
<rect key="frame" x="0.0" y="0.0" width="630" height="412"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<size key="minSize" width="536" height="235"/>
|
<size key="minSize" width="630" height="412"/>
|
||||||
<size key="maxSize" width="538" height="10000000"/>
|
<size key="maxSize" width="640" height="10000000"/>
|
||||||
<color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
<color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textView>
|
</textView>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
</clipView>
|
</clipView>
|
||||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="Kho-JF-NZJ">
|
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="Kho-JF-NZJ">
|
||||||
<rect key="frame" x="-100" y="-100" width="240" height="16"/>
|
<rect key="frame" x="-100" y="-100" width="240" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="qp7-7R-gTO">
|
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="qp7-7R-gTO">
|
||||||
<rect key="frame" x="521" y="1" width="16" height="235"/>
|
<rect key="frame" x="615" y="1" width="16" height="412"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
</scroller>
|
</scroller>
|
||||||
</scrollView>
|
</scrollView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="vZy-5S-021" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" constant="20" id="K0k-oE-r37"/>
|
<constraint firstItem="vZy-5S-021" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" constant="15" id="K0k-oE-r37"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="ICa-gx-jgq" secondAttribute="trailing" constant="20" id="LFS-0E-Ibw"/>
|
<constraint firstAttribute="trailing" secondItem="ICa-gx-jgq" secondAttribute="trailing" constant="15" id="LFS-0E-Ibw"/>
|
||||||
<constraint firstItem="vZy-5S-021" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="20" id="Nec-oI-CjE"/>
|
<constraint firstItem="vZy-5S-021" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="15" id="Nec-oI-CjE"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="vZy-5S-021" secondAttribute="trailing" constant="20" id="kBJ-O5-eYI"/>
|
<constraint firstAttribute="trailing" secondItem="vZy-5S-021" secondAttribute="trailing" constant="15" id="kBJ-O5-eYI"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="ICa-gx-jgq" secondAttribute="bottom" constant="20" id="kYB-Fn-DSA"/>
|
<constraint firstAttribute="bottom" secondItem="ICa-gx-jgq" secondAttribute="bottom" constant="15" id="kYB-Fn-DSA"/>
|
||||||
<constraint firstItem="ICa-gx-jgq" firstAttribute="top" secondItem="vZy-5S-021" secondAttribute="bottom" constant="10" id="xdn-yU-LVb"/>
|
<constraint firstItem="ICa-gx-jgq" firstAttribute="top" secondItem="vZy-5S-021" secondAttribute="bottom" constant="10" id="xdn-yU-LVb"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
|
<connections>
|
||||||
|
<outlet property="textView" destination="tN6-Y9-1pA" id="z77-me-Od6"/>
|
||||||
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="-147" y="294"/>
|
<point key="canvasLocation" x="-105" y="377.5"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
</document>
|
</document>
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
//
|
|
||||||
// ViewController.swift
|
|
||||||
// phpmon
|
|
||||||
//
|
|
||||||
// Created by Nico Verbruggen on 11/06/2019.
|
|
||||||
// Copyright © 2019 Nico Verbruggen. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Cocoa
|
|
||||||
|
|
||||||
class LogViewController: NSViewController {
|
|
||||||
|
|
||||||
@IBAction func pressed(_ sender: Any) {
|
|
||||||
self.view.window?.windowController?.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Reference in New Issue
Block a user