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

Add support for Homebrew in /opt/homebrew (#20)

This commit is contained in:
2021-01-01 22:54:03 +01:00
parent e73474e30c
commit 94f086881a
9 changed files with 124 additions and 34 deletions

View File

@ -26,6 +26,7 @@
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2322D70A4700B5F6B3 /* App.swift */; }; C4811D2422D70A4700B5F6B3 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2322D70A4700B5F6B3 /* App.swift */; };
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */; }; C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */; };
C486EFFC2586931100A02B2C /* PhpMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C486EFFB2586931100A02B2C /* PhpMenuItem.swift */; }; C486EFFC2586931100A02B2C /* PhpMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C486EFFB2586931100A02B2C /* PhpMenuItem.swift */; };
C49EAB46259FC305007F6C3B /* Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EAB45259FC305007F6C3B /* Paths.swift */; };
C4D8016622B1584700C6DA1B /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.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 */; }; C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F8C0A322D4F12C002EFE61 /* DateExtension.swift */; };
@ -54,6 +55,7 @@
C4811D2322D70A4700B5F6B3 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.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>"; }; C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
C486EFFB2586931100A02B2C /* PhpMenuItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpMenuItem.swift; sourceTree = "<group>"; }; C486EFFB2586931100A02B2C /* PhpMenuItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpMenuItem.swift; sourceTree = "<group>"; };
C49EAB45259FC305007F6C3B /* Paths.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Paths.swift; sourceTree = "<group>"; };
C4D8016522B1584700C6DA1B /* Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Startup.swift; sourceTree = "<group>"; }; C4D8016522B1584700C6DA1B /* Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Startup.swift; sourceTree = "<group>"; };
C4E713562570150F00007428 /* SECURITY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = SECURITY.md; sourceTree = "<group>"; }; C4E713562570150F00007428 /* SECURITY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = SECURITY.md; sourceTree = "<group>"; };
C4E713572570151400007428 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = "<group>"; }; C4E713572570151400007428 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = "<group>"; };
@ -149,6 +151,7 @@
C4811D2622D70CEF00B5F6B3 /* Singletons */ = { C4811D2622D70CEF00B5F6B3 /* Singletons */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
C49EAB45259FC305007F6C3B /* Paths.swift */,
C41C1B4622B009A400E7CF16 /* Shell.swift */, C41C1B4622B009A400E7CF16 /* Shell.swift */,
C42295DC2358D02000E263B2 /* Command.swift */, C42295DC2358D02000E263B2 /* Command.swift */,
C4811D2322D70A4700B5F6B3 /* App.swift */, C4811D2322D70A4700B5F6B3 /* App.swift */,
@ -272,6 +275,7 @@
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */, C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */,
C41C1B4B22B019FF00E7CF16 /* PhpVersion.swift in Sources */, C41C1B4B22B019FF00E7CF16 /* PhpVersion.swift in Sources */,
C486EFFC2586931100A02B2C /* PhpMenuItem.swift in Sources */, C486EFFC2586931100A02B2C /* PhpMenuItem.swift in Sources */,
C49EAB46259FC305007F6C3B /* Paths.swift in Sources */,
C476FF9822B0DD830098105B /* Alert.swift in Sources */, C476FF9822B0DD830098105B /* Alert.swift in Sources */,
C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */, C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */,
C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */, C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */,

View File

@ -33,6 +33,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
*/ */
let menu : MainMenu let menu : MainMenu
/**
The paths singleton that determines where Homebrew is installed,
and where to look for binaries.
*/
let paths : Paths
// MARK: - Initializer // MARK: - Initializer
/** /**
@ -42,6 +48,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
self.sharedShell = Shell.user self.sharedShell = Shell.user
self.state = App.shared self.state = App.shared
self.menu = MainMenu.shared self.menu = MainMenu.shared
self.paths = Paths.shared
super.init() super.init()
} }

View File

@ -12,7 +12,7 @@ import AppKit
class Actions { class Actions {
public static func detectPhpVersions() -> [String] { public static func detectPhpVersions() -> [String] {
let files = Shell.user.pipe("ls /usr/local/opt | grep php@") let files = Shell.user.pipe("ls \(Paths.optPath()) | grep php@")
var versions = files.components(separatedBy: "\n") var versions = files.components(separatedBy: "\n")
// Remove all empty strings // Remove all empty strings
@ -40,15 +40,15 @@ class Actions {
public static func restartPhpFpm() { public static func restartPhpFpm() {
let version = App.shared.currentVersion!.short let version = App.shared.currentVersion!.short
if (version == App.shared.brewPhpVersion) { if (version == App.shared.brewPhpVersion) {
Shell.user.run("sudo brew services restart php") Shell.user.run("sudo \(Paths.brew()) services restart php")
} else { } else {
Shell.user.run("sudo brew services restart php@\(version)") Shell.user.run("sudo \(Paths.brew()) services restart php@\(version)")
} }
} }
public static func restartNginx() public static func restartNginx()
{ {
Shell.user.run("sudo brew services restart nginx") Shell.user.run("sudo \(Paths.brew()) services restart nginx")
} }
/** /**
@ -63,22 +63,22 @@ class Actions {
public static func switchToPhpVersion(version: String, availableVersions: [String]) { public static func switchToPhpVersion(version: String, availableVersions: [String]) {
availableVersions.forEach { (available) in availableVersions.forEach { (available) in
let formula = (available == App.shared.brewPhpVersion) ? "php" : "php@\(available)" let formula = (available == App.shared.brewPhpVersion) ? "php" : "php@\(available)"
Shell.user.run("brew unlink \(formula)") Shell.user.run("\(Paths.brew()) unlink \(formula)")
Shell.user.run("sudo brew services stop \(formula)") Shell.user.run("sudo \(Paths.brew()) services stop \(formula)")
} }
let formula = (version == App.shared.brewPhpVersion) ? "php" : "php@\(version)" let formula = (version == App.shared.brewPhpVersion) ? "php" : "php@\(version)"
Shell.user.run("brew link \(formula) --overwrite --force") Shell.user.run("\(Paths.brew()) link \(formula) --overwrite --force")
Shell.user.run("sudo brew services start \(formula)") Shell.user.run("sudo \(Paths.brew()) services start \(formula)")
} }
public static func openGenericPhpConfigFolder() { public static func openGenericPhpConfigFolder() {
let files = [NSURL(fileURLWithPath: "/usr/local/etc/php")]; let files = [NSURL(fileURLWithPath: "\(Paths.etcPath())/php")];
NSWorkspace.shared.activateFileViewerSelecting(files as [URL]) NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
} }
public static func openPhpConfigFolder(version: String) { public static func openPhpConfigFolder(version: String) {
let files = [NSURL(fileURLWithPath: "/usr/local/etc/php/\(version)/php.ini")]; let files = [NSURL(fileURLWithPath: "\(Paths.etcPath())/php/\(version)/php.ini")];
NSWorkspace.shared.activateFileViewerSelecting(files as [URL]) NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
} }
@ -89,7 +89,7 @@ class Actions {
public static func didFindXdebug(_ version: String) -> Bool { public static func didFindXdebug(_ version: String) -> Bool {
let command = """ let command = """
grep -q 'zend_extension="xdebug.so"' /usr/local/etc/php/\(version)/php.ini; [ $? -eq 0 ] && echo "YES" || echo "NO" grep -q 'zend_extension="xdebug.so"' \(Paths.etcPath())/php/\(version)/php.ini; [ $? -eq 0 ] && echo "YES" || echo "NO"
""" """
let output = Shell.user.pipe(command).trimmingCharacters(in: .whitespacesAndNewlines) let output = Shell.user.pipe(command).trimmingCharacters(in: .whitespacesAndNewlines)
return (output == "YES") return (output == "YES")
@ -97,7 +97,7 @@ class Actions {
public static func didEnableXdebug(_ version: String) -> Bool { public static func didEnableXdebug(_ version: String) -> Bool {
let command = """ let command = """
grep -q '; zend_extension="xdebug.so"' /usr/local/etc/php/\(version)/php.ini; [ $? -eq 0 ] && echo "YES" || echo "NO" grep -q '; zend_extension="xdebug.so"' \(Paths.etcPath())/php/\(version)/php.ini; [ $? -eq 0 ] && echo "YES" || echo "NO"
""" """
let output = Shell.user.pipe(command).trimmingCharacters(in: .whitespacesAndNewlines) let output = Shell.user.pipe(command).trimmingCharacters(in: .whitespacesAndNewlines)
return (output == "NO") return (output == "NO")
@ -106,11 +106,11 @@ class Actions {
public static func toggleXdebug() { public static func toggleXdebug() {
let version = App.shared.currentVersion?.short let version = App.shared.currentVersion?.short
var command = """ var command = """
sed -i '' 's/; zend_extension="xdebug.so"/zend_extension="xdebug.so"/g' /usr/local/etc/php/\(version!)/php.ini sed -i '' 's/; zend_extension="xdebug.so"/zend_extension="xdebug.so"/g' \(Paths.etcPath())/php/\(version!)/php.ini
""" """
if (self.didEnableXdebug(version!)) { if (self.didEnableXdebug(version!)) {
command = """ command = """
sed -i '' 's/zend_extension="xdebug.so"/; zend_extension="xdebug.so"/g' /usr/local/etc/php/\(version!)/php.ini sed -i '' 's/zend_extension="xdebug.so"/; zend_extension="xdebug.so"/g' \(Paths.etcPath())/php/\(version!)/php.ini
""" """
} }
Shell.user.run(command) Shell.user.run(command)
@ -124,19 +124,19 @@ class Actions {
public static func fixMyPhp() { public static func fixMyPhp() {
let versions = self.detectPhpVersions() let versions = self.detectPhpVersions()
versions.forEach { (version) in versions.forEach { (version) in
Shell.user.run("brew unlink php@\(version)") Shell.user.run("\(Paths.brew()) unlink php@\(version)")
if (version == App.shared.brewPhpVersion) { if (version == App.shared.brewPhpVersion) {
Shell.user.run("brew services stop php") Shell.user.run("\(Paths.brew()) services stop php")
Shell.user.run("sudo brew services stop php") Shell.user.run("sudo \(Paths.brew()) services stop php")
} else { } else {
Shell.user.run("brew services stop php@\(version)") Shell.user.run("\(Paths.brew()) services stop php@\(version)")
Shell.user.run("sudo brew services stop php@\(version)") Shell.user.run("sudo \(Paths.brew()) services stop php@\(version)")
} }
} }
Shell.user.run("brew services stop php") Shell.user.run("\(Paths.brew()) services stop php")
Shell.user.run("brew services stop nginx") Shell.user.run("\(Paths.brew()) services stop nginx")
Shell.user.run("brew link php") Shell.user.run("\(Paths.brew()) link php")
Shell.user.run("sudo brew services restart php") Shell.user.run("sudo \(Paths.brew()) services restart php")
Shell.user.run("sudo brew services restart nginx") Shell.user.run("sudo \(Paths.brew()) services restart nginx")
} }
} }

View File

@ -25,14 +25,14 @@ class Startup {
self.failureCallback = failure self.failureCallback = failure
self.performEnvironmentCheck( self.performEnvironmentCheck(
!Shell.user.pipe("which php").contains("/usr/local/bin/php"), !Shell.fileExists("\(Paths.binPath())/php"),
messageText: "startup.errors.php_binary.title".localized, messageText: "startup.errors.php_binary.title".localized,
informativeText: "startup.errors.php_binary_desc".localized, informativeText: "startup.errors.php_binary_desc".localized,
breaking: true breaking: true
) )
self.performEnvironmentCheck( self.performEnvironmentCheck(
!Shell.user.pipe("ls /usr/local/opt | grep php").contains("php"), !Shell.user.pipe("ls \(Paths.optPath()) | grep php").contains("php"),
messageText: "startup.errors.php_opt.title".localized, messageText: "startup.errors.php_opt.title".localized,
informativeText: "startup.errors.php_opt.desc".localized, informativeText: "startup.errors.php_opt.desc".localized,
breaking: true breaking: true
@ -46,7 +46,7 @@ class Startup {
) )
self.performEnvironmentCheck( self.performEnvironmentCheck(
!Shell.user.pipe("cat /private/etc/sudoers.d/brew").contains("/usr/local/bin/brew"), !Shell.user.pipe("cat /private/etc/sudoers.d/brew").contains("\(Paths.binPath())/brew"),
messageText: "startup.errors.sudoers_brew.title".localized, messageText: "startup.errors.sudoers_brew.title".localized,
informativeText: "startup.errors.sudoers_brew.desc".localized, informativeText: "startup.errors.sudoers_brew.desc".localized,
breaking: true breaking: true
@ -59,7 +59,7 @@ class Startup {
breaking: true breaking: true
) )
let services = Shell.user.pipe("brew services list | grep php") let services = Shell.user.pipe("\(Paths.brew()) services list | grep php")
self.performEnvironmentCheck( self.performEnvironmentCheck(
(services.countInstances(of: "started") > 1), (services.countInstances(of: "started") > 1),
messageText: "startup.errors.services.title".localized, messageText: "startup.errors.services.title".localized,
@ -82,7 +82,7 @@ class Startup {
print("PHP Monitor has determined the application has successfully passed all checks.") print("PHP Monitor has determined the application has successfully passed all checks.")
print("Determining which version of PHP is aliased to `php` via Homebrew...") print("Determining which version of PHP is aliased to `php` via Homebrew...")
let brewPhpAlias = Shell.user.pipe("brew info php --json"); let brewPhpAlias = Shell.user.pipe("\(Paths.brew()) info php --json");
App.shared.brewPhpPackage = try! JSONDecoder().decode( App.shared.brewPhpPackage = try! JSONDecoder().decode(
[HomebrewPackage].self, [HomebrewPackage].self,

View File

@ -19,7 +19,10 @@ class PhpVersion {
var error : Bool = false var error : Bool = false
init() { init() {
let version = Command.execute(path: "/usr/local/bin/php", arguments: ["-r", "print phpversion();"]) let version = Command.execute(
path: Paths.php(),
arguments: ["-r", "print phpversion();"]
)
if (version == "" || version.contains("Warning")) { if (version == "" || version.contains("Warning")) {
self.short = "💩 BROKEN" self.short = "💩 BROKEN"

View File

@ -59,11 +59,11 @@
/// 1. PHP binary not found /// 1. PHP binary not found
"startup.errors.php_binary.title" = "PHP is not correctly installed"; "startup.errors.php_binary.title" = "PHP is not correctly installed";
"startup.errors.php_binary_desc" = "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. (Usually `brew link php` resolves this issue.)"; "startup.errors.php_binary_desc" = "You must install PHP via brew. Try running `which php` in Terminal, it should return `/usr/local/bin/php` (or `/opt/homebrew/bin/php`). The app will not work correctly until you resolve this issue. (Usually `brew link php` resolves this issue.)";
/// 2. PHP not found in /usr/local/opt /// 2. PHP not found in /usr/local/opt or /opt/homebrew/opt
"startup.errors.php_opt.title" = "PHP is not correctly installed"; "startup.errors.php_opt.title" = "PHP is not correctly installed";
"startup.errors.php_opt.desc" = "PHP alias was not found in `/usr/local/opt`. The app will not work correctly until you resolve this issue. If you already have the `php` formula installed, you may need to run `brew install php` in order for PHP Monitor to detect this installation."; "startup.errors.php_opt.desc" = "PHP alias was not found in `/usr/local/opt` (or `/opt/homebrew/opt`). The app will not work correctly until you resolve this issue. If you already have the `php` formula installed, you may need to run `brew install php` in order for PHP Monitor to detect this installation.";
/// 3. Valet not installed /// 3. Valet not installed
"startup.errors.valet_executable.title" = "Laravel Valet is not correctly installed"; "startup.errors.valet_executable.title" = "Laravel Valet is not correctly installed";

View File

@ -201,7 +201,7 @@ class MainMenu: NSObject, NSWindowDelegate {
@objc public func openPhpInfo() { @objc public func openPhpInfo() {
self.waitAndExecute({ self.waitAndExecute({
try! "<?php phpinfo();".write(toFile: "/tmp/phpmon_phpinfo.php", atomically: true, encoding: .utf8) try! "<?php phpinfo();".write(toFile: "/tmp/phpmon_phpinfo.php", atomically: true, encoding: .utf8)
Shell.user.run("/usr/local/bin/php-cgi -q /tmp/phpmon_phpinfo.php > /tmp/phpmon_phpinfo.html") Shell.user.run("\(Paths.binPath())/php-cgi -q /tmp/phpmon_phpinfo.php > /tmp/phpmon_phpinfo.html")
}, { }, {
NSWorkspace.shared.open(URL(string: "file:///private/tmp/phpmon_phpinfo.html")!) NSWorkspace.shared.open(URL(string: "file:///private/tmp/phpmon_phpinfo.html")!)
}) })

View File

@ -0,0 +1,70 @@
//
// Paths.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 01/01/2021.
// Copyright © 2021 Nico Verbruggen. All rights reserved.
//
import Foundation
enum HomebrewDirectory: String {
case opt = "/opt/homebrew/bin"
case usr = "/usr/local/bin"
}
class Paths {
static let shared = Paths()
var baseDirectory : HomebrewDirectory
init() {
let optBrewFound = Shell.fileExists("\(HomebrewDirectory.opt.rawValue)/brew")
let usrBrewFound = Shell.fileExists("\(HomebrewDirectory.usr.rawValue)/brew")
if (optBrewFound) {
self.baseDirectory = .opt
} else if (usrBrewFound) {
self.baseDirectory = .usr
} else {
// Falling back to Intel
print("Seems like we couldn't determine the architecture.")
print("This usually means we're in trouble... (no Homebrew?)")
self.baseDirectory = .usr
}
print("Homebrew directory: \(self.baseDirectory)")
}
public static func brew() -> String {
return "\(self.binPath())/brew"
}
public static func php() -> String {
return "\(self.binPath())/php"
}
public static func binPath() -> String {
return self.shared.baseDirectory.rawValue
}
public static func optPath() -> String {
switch self.shared.baseDirectory {
case .opt:
return "/opt/homebrew/opt"
case .usr:
return "/usr/local/opt"
}
}
public static func etcPath() -> String {
switch self.shared.baseDirectory {
case .opt:
return "/opt/homebrew/etc"
case .usr:
return "/usr/local/etc"
}
}
}

View File

@ -46,4 +46,10 @@ class Shell {
encoding: .utf8 encoding: .utf8
)! )!
} }
public static func fileExists(_ filePath: String) -> Bool {
return Shell.user.pipe(
"if [ -f \(filePath) ]; then echo \"Y\"; fi"
).contains("Y")
}
} }