1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-07 20:10:08 +02:00

Merge branch 'cleanup' into develop

* cleanup:
  ♻️ Menu refactor
  ♻️ Use Localizable.strings
  ♻️ Change default shell for commands, cleanup files
This commit is contained in:
2020-05-16 23:56:33 +02:00
10 changed files with 216 additions and 154 deletions

View File

@ -16,6 +16,8 @@
C41C1B4D22B0215A00E7CF16 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4C22B0215A00E7CF16 /* Actions.swift */; };
C42295DD2358D02000E263B2 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42295DC2358D02000E263B2 /* Command.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 */; };
C476FF9822B0DD830098105B /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C476FF9722B0DD830098105B /* Alert.swift */; };
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2322D70A4700B5F6B3 /* App.swift */; };
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */; };
@ -37,6 +39,8 @@
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>"; };
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>"; };
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>"; };
@ -86,6 +90,7 @@
C41C1B3F22B0098000E7CF16 /* Info.plist */,
C41C1B4022B0098000E7CF16 /* phpmon.entitlements */,
C41C1B3A22B0098000E7CF16 /* Assets.xcassets */,
C473319E2470923A009A0597 /* Localizable.strings */,
);
path = phpmon;
sourceTree = "<group>";
@ -93,6 +98,7 @@
C41E181722CB61EB0072CF09 /* Classes */ = {
isa = PBXGroup;
children = (
C47331A0247093AC009A0597 /* Menu */,
C4811D2722D70D8E00B5F6B3 /* Commands */,
C4811D2822D70D9C00B5F6B3 /* Helpers */,
);
@ -107,6 +113,14 @@
path = "View Controllers";
sourceTree = "<group>";
};
C47331A0247093AC009A0597 /* Menu */ = {
isa = PBXGroup;
children = (
C47331A1247093B7009A0597 /* StatusMenu.swift */,
);
path = Menu;
sourceTree = "<group>";
};
C4811D2622D70CEF00B5F6B3 /* Singletons */ = {
isa = PBXGroup;
children = (
@ -206,6 +220,7 @@
files = (
C41C1B3B22B0098000E7CF16 /* Assets.xcassets in Resources */,
C41C1B3E22B0098000E7CF16 /* Main.storyboard in Resources */,
C473319F2470923A009A0597 /* Localizable.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -227,6 +242,7 @@
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */,
C41C1B4B22B019FF00E7CF16 /* PhpVersion.swift in Sources */,
C476FF9822B0DD830098105B /* Alert.swift in Sources */,
C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */,
C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */,
C4EE188422D3386B00E126E5 /* Constants.swift in Sources */,
);

View File

@ -65,6 +65,11 @@ class Actions {
}
}
public static func openGenericPhpConfigFolder() {
let files = [NSURL(fileURLWithPath: "/usr/local/etc/php")];
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
}
public static func openPhpConfigFolder(version: String) {
let files = [NSURL(fileURLWithPath: "/usr/local/etc/php/\(version)/php.ini")];
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
@ -75,7 +80,7 @@ class Actions {
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
}
public static func XdebugFound(_ version: String) -> Bool {
public static func didFindXdebug(_ version: String) -> Bool {
let command = """
grep -q 'zend_extension="xdebug.so"' /usr/local/etc/php/\(version)/php.ini; [ $? -eq 0 ] && echo "YES" || echo "NO"
"""
@ -83,7 +88,7 @@ class Actions {
return (output == "YES")
}
public static func XdebugEnabled(_ version: String) -> Bool {
public static func didEnableXdebug(_ version: String) -> Bool {
let command = """
grep -q '; zend_extension="xdebug.so"' /usr/local/etc/php/\(version)/php.ini; [ $? -eq 0 ] && echo "YES" || echo "NO"
"""
@ -96,7 +101,7 @@ class Actions {
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!)) {
if (self.didEnableXdebug(version!)) {
command = """
sed -i '' 's/zend_extension="xdebug.so"/; zend_extension="xdebug.so"/g' /usr/local/etc/php/\(version!)/php.ini
"""

View File

@ -38,9 +38,9 @@ class PhpVersion {
self.short = segments[0...1].joined(separator: ".")
// Load xdebug support
self.xdebugFound = Actions.XdebugFound(self.short)
self.xdebugFound = Actions.didFindXdebug(self.short)
if (self.xdebugFound) {
self.xdebugEnabled = Actions.XdebugEnabled(self.short)
self.xdebugEnabled = Actions.didEnableXdebug(self.short)
}
self.error = false;

View File

@ -0,0 +1,88 @@
//
// MainMenuBuilder.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 16/05/2020.
// Copyright © 2020 Nico Verbruggen. All rights reserved.
//
import Cocoa
class StatusMenu : NSMenu {
public func addPhpVersionMenuItems()
{
var string = "We are not sure what version of PHP you are running."
if (App.shared.currentVersion != nil) {
if (!App.shared.currentVersion!.error) {
string = "You are running PHP \(App.shared.currentVersion!.long)"
self.addItem(NSMenuItem(title: string, action: nil, keyEquivalent: ""))
} else {
// in case of an error show the error message
self.addItem(NSMenuItem(title: "Oof! It appears your PHP installation is broken...", action: nil, keyEquivalent: ""))
self.addItem(NSMenuItem(title: "Try running `php -v` in your terminal.", action: nil, keyEquivalent: ""))
self.addItem(NSMenuItem(title: "You could also try switching to another version.", action: nil, keyEquivalent: ""))
self.addItem(NSMenuItem(title: "Running `brew reinstall php` (or for the equivalent version) might help.", action: nil, keyEquivalent: ""))
}
}
}
public func addPhpActionMenuItems()
{
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(MainMenu.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
self.addItem(menuItem)
}
self.addItem(NSMenuItem.separator())
self.addItem(NSMenuItem(title: "Active Services", action: nil, keyEquivalent: ""))
self.addItem(NSMenuItem(title: "Restart php-fpm service", action: #selector(MainMenu.restartPhpFpm), keyEquivalent: "f"))
self.addItem(NSMenuItem(title: "Restart nginx service", action: #selector(MainMenu.restartNginx), keyEquivalent: "n"))
self.addItem(NSMenuItem(title: "Force load latest PHP version", action: #selector(MainMenu.forceRestartLatestPhp), keyEquivalent: ""))
}
if (App.shared.busy) {
self.addItem(NSMenuItem(title: "PHP Monitor is busy...", action: nil, keyEquivalent: ""))
}
}
public func addPhpConfigurationMenuItems()
{
if (App.shared.currentVersion != nil) {
self.addItem(NSMenuItem(title: "Configuration", action: nil, keyEquivalent: ""))
self.addItem(NSMenuItem(title: "Valet configuration (.config/valet)", action: #selector(MainMenu.openValetConfigFolder), keyEquivalent: "v"))
self.addItem(NSMenuItem(title: "PHP configuration file (php.ini)", action: #selector(MainMenu.openActiveConfigFolder), keyEquivalent: "c"))
self.addItem(NSMenuItem.separator())
self.addItem(NSMenuItem(title: "Enabled Extensions", action: nil, keyEquivalent: ""))
self.addXdebugMenuItem()
}
}
private func addXdebugMenuItem()
{
let xdebugFound = App.shared.currentVersion!.xdebugFound
if (xdebugFound) {
let xdebugOn = App.shared.currentVersion!.xdebugEnabled
let xdebugToggleMenuItem = NSMenuItem(
title: "Xdebug",
action: #selector(MainMenu.toggleXdebug), keyEquivalent: "x"
)
if (xdebugOn) {
xdebugToggleMenuItem.state = .on
}
self.addItem(xdebugToggleMenuItem)
} else {
let disabledItem = NSMenuItem(
title: "xdebug.so missing",
action: nil, keyEquivalent: "x"
)
disabledItem.isEnabled = false
self.addItem(disabledItem)
}
}
}

View File

@ -10,8 +10,7 @@ import Cocoa
extension Date
{
func toString() -> String
{
func toString() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter.string(from: self)

View File

@ -9,14 +9,24 @@
import Foundation
extension String {
var localized: String {
return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
}
func countInstances(of stringToFind: String) -> Int {
assert(!stringToFind.isEmpty)
if (stringToFind.isEmpty) {
return 0
}
var count = 0
var searchRange: Range<String.Index>?
while let foundRange = range(of: stringToFind, options: [], range: searchRange) {
count += 1
searchRange = Range(uncheckedBounds: (lower: foundRange.upperBound, upper: endIndex))
}
return count
}
}

View File

@ -0,0 +1,17 @@
/*
Strings.strings
PHP Monitor
Created by Nico Verbruggen on 16/05/2020.
Copyright © 2020 Nico Verbruggen. All rights reserved.
*/
// ALERTS
// Force Reload Started
"alert.force_reload.title" = "PHP Monitor will force reload the latest version of PHP";
"alert.force_reload.info" = "This can take a while. You'll get another alert when the force reload has completed.";
// Force Reload Done
"alert.force_reload_done.title" = "PHP has been force reloaded";
"alert.force_reload_done.info" = "All appropriate services have been restarted, and the latest version of PHP is now active. You can now try switching to another version of PHP.";

View File

@ -24,27 +24,4 @@ class Command {
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")
*/
}
}

View File

@ -39,75 +39,31 @@ class MainMenu: NSObject, NSWindowDelegate {
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) {
if (!App.shared.currentVersion!.error) {
string = "You are running PHP \(App.shared.currentVersion!.long)"
menu.addItem(NSMenuItem(title: string, action: nil, keyEquivalent: ""))
} else {
// in case of an error show the error message
menu.addItem(NSMenuItem(title: "Oof! It appears your PHP installation is broken...", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Try running `php -v` in your terminal.", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "You could also try switching to another version.", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Running `brew reinstall php` (or for the equivalent version) might help.", action: nil, keyEquivalent: ""))
}
}
// Create a new menu
let menu = StatusMenu()
// Add the PHP versions (or error messages)
menu.addPhpVersionMenuItems()
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())
menu.addItem(NSMenuItem(title: "Active Services", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Restart php-fpm service", action: #selector(self.restartPhpFpm), keyEquivalent: "f"))
menu.addItem(NSMenuItem(title: "Restart nginx service", action: #selector(self.restartNginx), keyEquivalent: "n"))
menu.addItem(NSMenuItem(title: "Force load latest PHP version", action: #selector(self.fixMyPhp), keyEquivalent: ""))
menu.addItem(NSMenuItem.separator())
}
if (App.shared.busy) {
menu.addItem(NSMenuItem(title: "PHP Monitor is busy...", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem.separator())
}
if (App.shared.currentVersion != nil) {
menu.addItem(NSMenuItem(title: "Configuration", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Valet configuration (.config/valet)", action: #selector(self.openValetConfigFolder), keyEquivalent: "v"))
menu.addItem(NSMenuItem(title: "PHP configuration file (php.ini)", action: #selector(self.openActiveConfigFolder), keyEquivalent: "c"))
menu.addItem(NSMenuItem.separator())
menu.addItem(NSMenuItem(title: "Enabled Extensions", action: nil, keyEquivalent: ""))
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)
}
}
// Add the possible actions
menu.addPhpActionMenuItems()
menu.addItem(NSMenuItem.separator())
// Add information about services & actions
menu.addPhpConfigurationMenuItems()
menu.addItem(NSMenuItem.separator())
// Add about & quit menu items
menu.addItem(NSMenuItem(title: "About PHP Monitor", action: #selector(self.openAbout), keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Quit PHP Monitor", action: #selector(self.terminateApp), keyEquivalent: "q"))
// Make sure every item can be interacted with
menu.items.forEach({ (item) in
item.target = self
})
menu.addItem(NSMenuItem(title: "Quit PHP Monitor", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
// Update the menu item on the main thread
DispatchQueue.main.async {
self.statusItem.menu = menu
}
@ -115,11 +71,7 @@ class MainMenu: NSObject, NSWindowDelegate {
}
func setStatusBarImage(version: String) {
self.setStatusBar(
image: MenuBarImageGenerator.textToImage(
text: version
)
)
self.setStatusBar(image: MenuBarImageGenerator.textToImage(text: version))
}
func setStatusBar(image: NSImage) {
@ -129,7 +81,25 @@ class MainMenu: NSObject, NSWindowDelegate {
}
}
// MARK: - Callable via Obj-C (#selector)
// MARK: - Nicer callbacks
private func waitAndExecute(_ execute: @escaping () -> Void, _ completion: @escaping () -> Void = {})
{
App.shared.busy = true
self.setBusyImage()
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
self.update()
execute()
App.shared.busy = false
DispatchQueue.main.async {
self.updatePhpVersionInStatusBar()
self.update()
completion()
}
}
}
// MARK: - Actions & Menu Manipulation
@objc func updatePhpVersionInStatusBar() {
App.shared.currentVersion = PhpVersion()
@ -151,21 +121,6 @@ class MainMenu: NSObject, NSWindowDelegate {
}
}
private func waitAndExecute(_ execute: @escaping () -> Void)
{
App.shared.busy = true
self.setBusyImage()
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
self.update()
execute()
App.shared.busy = false
DispatchQueue.main.async {
self.updatePhpVersionInStatusBar()
self.update()
}
}
}
@objc public func restartPhpFpm() {
self.waitAndExecute({
Actions.restartPhpFpm()
@ -178,13 +133,34 @@ class MainMenu: NSObject, NSWindowDelegate {
})
}
@objc public func openAbout() {
NSApplication.shared.activate(ignoringOtherApps: true)
NSApplication.shared.orderFrontStandardAboutPanel()
@objc public func toggleXdebug() {
self.waitAndExecute({
Actions.toggleXdebug()
})
}
@objc public func forceRestartLatestPhp() {
Alert.present(
messageText: "alert.force_reload.title".localized,
informativeText: "alert.force_reload.info".localized
)
self.waitAndExecute({ Actions.fixMyPhp() }, {
Alert.present(
messageText: "alert.force_reload_done.title".localized,
informativeText: "alert.force_reload_done.info".localized
)
})
}
@objc public func openActiveConfigFolder() {
Actions.openPhpConfigFolder(version: App.shared.currentVersion!.short)
if (App.shared.currentVersion!.error) {
// php version was not identified
Actions.openGenericPhpConfigFolder()
} else {
// php version was identified
Actions.openPhpConfigFolder(version: App.shared.currentVersion!.short)
}
}
@objc public func openValetConfigFolder() {
@ -216,37 +192,17 @@ class MainMenu: NSObject, NSWindowDelegate {
}
}
@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()
}
}
@objc public func openAbout() {
NSApplication.shared.activate(ignoringOtherApps: true)
NSApplication.shared.orderFrontStandardAboutPanel()
}
@objc public func fixMyPhp() {
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
DispatchQueue.main.async {
Alert.present(messageText: "PHP Monitor will force reload the latest version of PHP", informativeText: "This can take a while. You'll get another alert when the force reload has completed.")
App.shared.busy = true
self.updatePhpVersionInStatusBar()
self.update()
}
Actions.fixMyPhp()
DispatchQueue.main.async {
Alert.present(messageText: "PHP has been force reloaded", informativeText: "All appropriate services have been restarted, and the latest version of PHP is now active. You can now try switching to another version of PHP.")
App.shared.busy = false
self.updatePhpVersionInStatusBar()
self.update()
}
}
@objc public func terminateApp() {
NSApplication.shared.terminate(nil)
}
// MARK: - Cleanup when window closes
func windowWillClose(_ notification: Notification) {
App.shared.windowController = nil
Shell.user.delegate = nil

View File

@ -40,9 +40,9 @@ class Shell {
}
/// Runs a shell command and returns the output.
public func pipe(_ command: String) -> String {
public func pipe(_ command: String, shell: String = "/bin/sh") -> String {
let task = Process()
task.launchPath = "/bin/bash"
task.launchPath = shell
task.arguments = ["--login", "-c", command]
let pipe = Pipe()
@ -51,13 +51,7 @@ class Shell {
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 output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String
let historyItem = ShellHistoryItem(command: command, output: output)