1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2026-04-07 03:20:09 +02:00

♻️ Even more refactoring

This commit is contained in:
2025-10-09 16:05:32 +02:00
parent 372c11f924
commit 9e76ca7b25
45 changed files with 230 additions and 223 deletions

View File

@@ -15,6 +15,7 @@ public struct ContainerAccessMacro: MemberMacro {
("shell", "ShellProtocol"),
("filesystem", "FileSystemProtocol"),
("command", "CommandProtocol"),
("paths", "Paths"),
("favorites", "Favorites"),
("warningManager", "WarningManager")
]

View File

@@ -7,62 +7,56 @@
import Foundation
import AppKit
import ContainerMacro
@ContainerAccess
class Actions {
var container: Container
init(
container: Container = App.shared.container,
) {
self.container = container
}
// MARK: - Services
public static func linkPhp() async {
public func linkPhp() async {
await brew("link php --overwrite --force")
}
public static func restartPhpFpm() async {
public func restartPhpFpm() async {
await brew("services restart \(HomebrewFormulae.php)", sudo: HomebrewFormulae.php.elevated)
}
public static func restartPhpFpm(version: String) async {
public func restartPhpFpm(version: String) async {
let formula = (version == PhpEnvironments.brewPhpAlias) ? "php" : "php@\(version)"
await brew("services restart \(formula)", sudo: HomebrewFormulae.php.elevated)
}
public static func restartNginx() async {
public func restartNginx() async {
await brew("services restart \(HomebrewFormulae.nginx)", sudo: HomebrewFormulae.nginx.elevated)
}
public static func restartDnsMasq() async {
public func restartDnsMasq() async {
await brew("services restart \(HomebrewFormulae.dnsmasq)", sudo: HomebrewFormulae.dnsmasq.elevated)
}
public static func stopValetServices() async {
public func stopValetServices() async {
await brew("services stop \(HomebrewFormulae.php)", sudo: HomebrewFormulae.php.elevated)
await brew("services stop \(HomebrewFormulae.nginx)", sudo: HomebrewFormulae.nginx.elevated)
await brew("services stop \(HomebrewFormulae.dnsmasq)", sudo: HomebrewFormulae.dnsmasq.elevated)
}
public static func fixHomebrewPermissions() throws {
public func fixHomebrewPermissions() throws {
var servicesCommands = [
"\(Paths.brew) services stop \(HomebrewFormulae.nginx)",
"\(Paths.brew) services stop \(HomebrewFormulae.dnsmasq)"
"\(paths.brew) services stop \(HomebrewFormulae.nginx)",
"\(paths.brew) services stop \(HomebrewFormulae.dnsmasq)"
]
var cellarCommands = [
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/\(HomebrewFormulae.nginx)",
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/\(HomebrewFormulae.dnsmasq)"
"chown -R \(paths.whoami):admin \(paths.cellarPath)/\(HomebrewFormulae.nginx)",
"chown -R \(paths.whoami):admin \(paths.cellarPath)/\(HomebrewFormulae.dnsmasq)"
]
PhpEnvironments.shared.availablePhpVersions.forEach { version in
let formula = version == PhpEnvironments.brewPhpAlias
? "php"
: "php@\(version)"
servicesCommands.append("\(Paths.brew) services stop \(formula)")
cellarCommands.append("chown -R \(Paths.whoami):admin \(Paths.cellarPath)/\(formula)")
servicesCommands.append("\(paths.brew) services stop \(formula)")
cellarCommands.append("chown -R \(paths.whoami):admin \(paths.cellarPath)/\(formula)")
}
let script =
@@ -84,27 +78,27 @@ class Actions {
// MARK: - Finding Config Files
public static func openGenericPhpConfigFolder() {
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php")]
public func openGenericPhpConfigFolder() {
let files = [NSURL(fileURLWithPath: "\(paths.etcPath)/php")]
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
}
public static func openPhpConfigFolder(version: String) {
let files = [NSURL(fileURLWithPath: "\(Paths.etcPath)/php/\(version)/php.ini")]
public func openPhpConfigFolder(version: String) {
let files = [NSURL(fileURLWithPath: "\(paths.etcPath)/php/\(version)/php.ini")]
NSWorkspace.shared.activateFileViewerSelecting(files as [URL])
}
public static func openGlobalComposerFolder() {
public func openGlobalComposerFolder() {
let file = URL(string: "file://~/.composer/composer.json".replacingTildeWithHomeDirectory)!
NSWorkspace.shared.activateFileViewerSelecting([file] as [URL])
}
public static func openValetConfigFolder() {
public func openValetConfigFolder() {
let file = URL(string: "file://~/.config/valet".replacingTildeWithHomeDirectory)!
NSWorkspace.shared.activateFileViewerSelecting([file] as [URL])
}
public static func openPhpMonitorConfigFile() {
public func openPhpMonitorConfigFile() {
let file = URL(string: "file://~/.config/phpmon".replacingTildeWithHomeDirectory)!
NSWorkspace.shared.activateFileViewerSelecting([file] as [URL])
}
@@ -112,10 +106,10 @@ class Actions {
// MARK: - Other Actions
public func createTempPhpInfoFile() async -> URL {
try! container.filesystem.writeAtomicallyToFile("/tmp/phpmon_phpinfo.php", content: "<?php phpinfo();")
try! filesystem.writeAtomicallyToFile("/tmp/phpmon_phpinfo.php", content: "<?php phpinfo();")
// Tell php-cgi to run the PHP and output as an .html file
await container.shell.quiet("\(Paths.binPath)/php-cgi -q /tmp/phpmon_phpinfo.php > /tmp/phpmon_phpinfo.html")
await shell.quiet("\(paths.binPath)/php-cgi -q /tmp/phpmon_phpinfo.php > /tmp/phpmon_phpinfo.html")
return URL(string: "file:///private/tmp/phpmon_phpinfo.html")!
}
@@ -134,7 +128,7 @@ class Actions {
If this does not solve the issue, the user may need to install additional
extensions and/or run `composer global update`.
*/
public static func fixMyValet() async {
public func fixMyValet() async {
await InternalSwitcher().performSwitch(to: PhpEnvironments.brewPhpAlias)
await brew("services restart \(HomebrewFormulae.dnsmasq)", sudo: HomebrewFormulae.dnsmasq.elevated)
await brew("services restart \(HomebrewFormulae.php)", sudo: HomebrewFormulae.php.elevated)

View File

@@ -13,8 +13,12 @@ import Foundation
/**
Runs a `brew` command. Can run as superuser.
*/
func brew(_ command: String, sudo: Bool = false, shell: ShellProtocol = App.shared.container.shell) async {
await shell.quiet("\(sudo ? "sudo " : "")" + "\(Paths.brew) \(command)")
func brew(
_ command: String,
sudo: Bool = false,
container: Container = App.shared.container,
) async {
await container.shell.quiet("\(sudo ? "sudo " : "")" + "\(container.paths.brew) \(command)")
}
/**
@@ -25,7 +29,8 @@ func sed(
original: String,
replacement: String,
filesystem: FileSystemProtocol = App.shared.container.filesystem,
shell: ShellProtocol = App.shared.container.shell
shell: ShellProtocol = App.shared.container.shell,
paths: Paths = App.shared.container.paths,
) async {
// Escape slashes (or `sed` won't work)
let e_original = original.replacingOccurrences(of: "/", with: "\\/")
@@ -33,8 +38,8 @@ func sed(
// Check if gsed exists; it is able to follow symlinks,
// which we want to do to toggle the extension
if filesystem.fileExists("\(Paths.binPath)/gsed") {
await shell.quiet("\(Paths.binPath)/gsed -i --follow-symlinks 's/\(e_original)/\(e_replacement)/g' \(file)")
if filesystem.fileExists("\(paths.binPath)/gsed") {
await shell.quiet("\(paths.binPath)/gsed -i --follow-symlinks 's/\(e_original)/\(e_replacement)/g' \(file)")
} else {
await shell.quiet("sed -i '' 's/\(e_original)/\(e_replacement)/g' \(file)")
}

View File

@@ -12,21 +12,19 @@ import Foundation
The path to the Homebrew directory and the user's name are fetched only once, at boot.
*/
public class Paths {
public static let shared = Paths()
internal let container: Container
internal var baseDir: Paths.HomebrewDir
private var userName: String
private var preferredShell: String
init() {
init(container: Container = App.shared.container) {
// Assume the default directory is correct
baseDir = App.architecture != "x86_64" ? .opt : .usr
// Ensure that if a different location is used, it takes precendence
if baseDir == .usr
&& App.shared.container.filesystem.directoryExists("/usr/local/homebrew")
&& !App.shared.container.filesystem.directoryExists("/usr/local/Cellar") {
&& container.filesystem.directoryExists("/usr/local/homebrew")
&& !container.filesystem.directoryExists("/usr/local/Cellar") {
Log.warn("Using /usr/local/homebrew as base directory!")
baseDir = .usr_hb
}
@@ -38,6 +36,8 @@ public class Paths {
Log.info("The current username is `\(userName)`.")
Log.info("The user's shell is `\(preferredShell)`.")
}
self.container = container
}
public func detectBinaryPaths() {
@@ -46,76 +46,76 @@ public class Paths {
// - MARK: Binaries
public static var valet: String {
public var valet: String {
return "\(binPath)/valet"
}
public static var brew: String {
public var brew: String {
return "\(binPath)/brew"
}
public static var php: String {
public var php: String {
return "\(binPath)/php"
}
public static var phpConfig: String {
public var phpConfig: String {
return "\(binPath)/php-config"
}
// - MARK: Detected Binaries
/** The path to the Composer binary. Can be in multiple locations, so is detected instead. */
public static var composer: String?
public var composer: String?
// - MARK: Paths
public static var whoami: String {
return shared.userName
public var whoami: String {
return userName
}
public static var homePath: String {
if App.shared.container.filesystem is RealFileSystem {
public var homePath: String {
if container.filesystem is RealFileSystem {
return NSHomeDirectory()
}
if App.shared.container.filesystem is TestableFileSystem {
let fs = App.shared.container.filesystem as! TestableFileSystem
if container.filesystem is TestableFileSystem {
let fs = container.filesystem as! TestableFileSystem
return fs.homeDirectory
}
fatalError("A valid FileSystem must be allowed to return the home path")
}
public static var cellarPath: String {
return "\(shared.baseDir.rawValue)/Cellar"
public var cellarPath: String {
return "\(baseDir.rawValue)/Cellar"
}
public static var binPath: String {
return "\(shared.baseDir.rawValue)/bin"
public var binPath: String {
return "\(baseDir.rawValue)/bin"
}
public static var optPath: String {
return "\(shared.baseDir.rawValue)/opt"
public var optPath: String {
return "\(baseDir.rawValue)/opt"
}
public static var etcPath: String {
return "\(shared.baseDir.rawValue)/etc"
public var etcPath: String {
return "\(baseDir.rawValue)/etc"
}
public static var tapPath: String {
if shared.baseDir == .usr {
return "\(shared.baseDir.rawValue)/homebrew/Library/Taps"
public var tapPath: String {
if baseDir == .usr {
return "\(baseDir.rawValue)/homebrew/Library/Taps"
}
return "\(shared.baseDir.rawValue)/Library/Taps"
return "\(baseDir.rawValue)/Library/Taps"
}
public static var caskroomPath: String {
return "\(shared.baseDir.rawValue)/Caskroom/phpmon"
public var caskroomPath: String {
return "\(baseDir.rawValue)/Caskroom/phpmon"
}
public static var shell: String {
return shared.preferredShell
public var shell: String {
return preferredShell
}
// MARK: - Flexible Binaries
@@ -123,14 +123,14 @@ public class Paths {
// (PHP Monitor will not use the user's own PATH)
private func detectComposerBinary() {
if App.shared.container.filesystem.fileExists("/usr/local/bin/composer") {
Paths.composer = "/usr/local/bin/composer"
} else if App.shared.container.filesystem.fileExists("/opt/homebrew/bin/composer") {
Paths.composer = "/opt/homebrew/bin/composer"
} else if App.shared.container.filesystem.fileExists("/usr/local/homebrew/bin/composer") {
Paths.composer = "/usr/local/homebrew/bin/composer"
if container.filesystem.fileExists("/usr/local/bin/composer") {
composer = "/usr/local/bin/composer"
} else if container.filesystem.fileExists("/opt/homebrew/bin/composer") {
composer = "/opt/homebrew/bin/composer"
} else if container.filesystem.fileExists("/usr/local/homebrew/bin/composer") {
composer = "/usr/local/homebrew/bin/composer"
} else {
Paths.composer = nil
composer = nil
Log.warn("Composer was not found.")
}
}

View File

@@ -10,7 +10,7 @@ import Foundation
extension String {
var replacingTildeWithHomeDirectory: String {
return self.replacingOccurrences(of: "~", with: Paths.homePath)
return self.replacingOccurrences(of: "~", with: App.shared.container.paths.homePath)
}
}

View File

@@ -41,7 +41,9 @@ class ActivePhpInstallation {
// MARK: - Initializer
public static func load() -> ActivePhpInstallation? {
if !App.shared.container.filesystem.fileExists(Paths.phpConfig) {
let container = App.shared.container
if !container.filesystem.fileExists(container.paths.phpConfig) {
return nil
}
@@ -75,7 +77,7 @@ class ActivePhpInstallation {
)
let paths = shell
.sync("\(Paths.php) --ini | grep -E -o '(/[^ ]+\\.ini)'").out
.sync("\(container.paths.php) --ini | grep -E -o '(/[^ ]+\\.ini)'").out
.split(separator: "\n")
.map { String($0) }
@@ -92,7 +94,7 @@ class ActivePhpInstallation {
_or_ if the output contains the word "Warning" or "Error". In normal situations this should not be the case.
*/
private func determineVersion() throws {
let output = command.execute(path: Paths.phpConfig, arguments: ["--version"], trimNewlines: true)
let output = command.execute(path: container.paths.phpConfig, arguments: ["--version"], trimNewlines: true)
self.hasErrorState = (output == "" || output.contains("Warning") || output.contains("Error"))
@@ -115,7 +117,7 @@ class ActivePhpInstallation {
- Parameter key: The key of the `ini` value that needs to be retrieved. For example, you can use `memory_limit`.
*/
private func getByteCount(key: String) -> String {
let value = command.execute(path: Paths.php, arguments: ["-r", "echo ini_get('\(key)');"], trimNewlines: false)
let value = command.execute(path: container.paths.php, arguments: ["-r", "echo ini_get('\(key)');"], trimNewlines: false)
// Check if the value is unlimited
if value == "-1" {

View File

@@ -32,7 +32,7 @@ class PhpEnvironments {
Determine which PHP version the `php` formula is aliased to.
*/
@MainActor func determinePhpAlias() async {
let brewPhpAlias = await container.shell.pipe("\(Paths.brew) info php --json").out
let brewPhpAlias = await container.shell.pipe("\(container.paths.brew) info php --json").out
self.homebrewPackage = try! JSONDecoder().decode(
[HomebrewPackage].self,
@@ -43,7 +43,7 @@ class PhpEnvironments {
Log.info("[BREW] On your system, the `php` formula means version \(homebrewPackage.version).")
// Check if that version actually corresponds to an older version
let phpConfigExecutablePath = "\(Paths.optPath)/php/bin/php-config"
let phpConfigExecutablePath = "\(container.paths.optPath)/php/bin/php-config"
if container.filesystem.fileExists(phpConfigExecutablePath) {
let longVersionString = container.command.execute(
path: phpConfigExecutablePath,
@@ -164,7 +164,7 @@ class PhpEnvironments {
Returns a `Set<String>` of installations that are considered valid.
*/
public func detectPhpVersions() async -> Set<String> {
let files = await container.shell.pipe("ls \(Paths.optPath) | grep php@").out
let files = await container.shell.pipe("ls \(container.paths.optPath) | grep php@").out
let versions = await extractPhpVersions(from: files.components(separatedBy: "\n"))
@@ -184,7 +184,7 @@ class PhpEnvironments {
let phpAlias = homebrewPackage.version
// Avoid inserting a duplicate
if !supportedVersions.contains(phpAlias) && container.filesystem.fileExists("\(Paths.optPath)/php/bin/php") {
if !supportedVersions.contains(phpAlias) && container.filesystem.fileExists("\(container.paths.optPath)/php/bin/php") {
let phpAliasInstall = PhpInstallation(phpAlias)
// Before inserting, ensure that the actual output matches the alias
// if that isn't the case, our formula remains out-of-date
@@ -237,7 +237,7 @@ class PhpEnvironments {
// is supported and where the binary exists (avoids broken installs)
if !output.contains(version)
&& supported.contains(version)
&& (checkBinaries ? container.filesystem.fileExists("\(Paths.optPath)/php@\(version)/bin/php") : true) {
&& (checkBinaries ? container.filesystem.fileExists("\(container.paths.optPath)/php@\(version)/bin/php") : true) {
output.insert(version)
}
}

View File

@@ -11,22 +11,21 @@ import Foundation
class PhpHelper {
static let keyPhrase = "This file was automatically generated by PHP Monitor."
static var container: Container {
return App.shared.container
}
public static func generate(for version: String) async {
public static func generate(
for version: String,
container: Container = App.shared.container
) async {
// Take the PHP version (e.g. "7.2") and generate a dotless version
let dotless = version.replacingOccurrences(of: ".", with: "")
// Determine the dotless name for this PHP version
let destination = "\(Paths.homePath)/.config/phpmon/bin/pm\(dotless)"
let destination = "\(container.paths.homePath)/.config/phpmon/bin/pm\(dotless)"
// Check if the ~/.config/phpmon/bin directory is in the PATH
let inPath = container.shell.PATH.contains("\(Paths.homePath)/.config/phpmon/bin")
let inPath = container.shell.PATH.contains("\(container.paths.homePath)/.config/phpmon/bin")
// Check if we can create symlinks (`/usr/local/bin` must be writable)
let canWriteSymlinks = App.shared.container.filesystem.isWriteableFile("/usr/local/bin/")
let canWriteSymlinks = container.filesystem.isWriteableFile("/usr/local/bin/")
Task { // Create the appropriate folders and check if the files exist
do {
@@ -49,11 +48,11 @@ class PhpHelper {
}
// Let's follow the symlink to the PHP binary folder
let path = URL(fileURLWithPath: "\(Paths.optPath)/php@\(version)/bin")
let path = URL(fileURLWithPath: "\(container.paths.optPath)/php@\(version)/bin")
.resolvingSymlinksInPath().path
// Check if the user uses Fish
let script = Paths.shell.contains("/fish")
let script = container.paths.shell.contains("/fish")
? fishScript(path, keyPhrase, version, dotless)
: zshScript(path, keyPhrase, version, dotless)
@@ -105,10 +104,11 @@ class PhpHelper {
_ path: String,
_ keyPhrase: String,
_ version: String,
_ dotless: String
_ dotless: String,
container: Container = App.shared.container
) -> String {
return """
#!\(Paths.binPath)/fish
#!\(container.paths.binPath)/fish
# \(keyPhrase)
# It reflects the location of PHP \(version)'s binaries on your system.
# Usage: . pm\(dotless)
@@ -117,11 +117,14 @@ class PhpHelper {
"""
}
private static func createSymlink(_ dotless: String) async {
let source = "\(Paths.homePath)/.config/phpmon/bin/pm\(dotless)"
private static func createSymlink(
_ dotless: String,
container: Container = App.shared.container
) async {
let source = "\(container.paths.homePath)/.config/phpmon/bin/pm\(dotless)"
let destination = "/usr/local/bin/pm\(dotless)"
if !App.shared.container.filesystem.fileExists(destination) {
if !container.filesystem.fileExists(destination) {
Log.info("Creating new symlink: \(destination)")
await container.shell.quiet("ln -s \(source) \(destination)")
return

View File

@@ -31,8 +31,11 @@ class PhpConfigurationFile: CreatedFromFile {
var lines: [String]
/** Resolves a PHP configuration file (.ini) */
static func from(filePath: String) -> Self? {
let path = filePath.replacingOccurrences(of: "~", with: Paths.homePath)
static func from(
filePath: String,
container: Container = App.shared.container
) -> Self? {
let path = filePath.replacingOccurrences(of: "~", with: container.paths.homePath)
do {
let fileContents = try App.shared.container.filesystem.getStringFromFile(path)

View File

@@ -43,8 +43,8 @@ class PhpInstallation {
init(container: Container = App.shared.container, _ version: String) {
self.container = container
let phpConfigExecutablePath = "\(Paths.optPath)/php@\(version)/bin/php-config",
phpExecutablePath = "\(Paths.optPath)/php@\(version)/bin/php"
let phpConfigExecutablePath = "\(container.paths.optPath)/php@\(version)/bin/php-config",
phpExecutablePath = "\(container.paths.optPath)/php@\(version)/bin/php"
versionNumber = VersionNumber.make(from: version)!

View File

@@ -30,12 +30,12 @@ extension InternalSwitcher {
// MARK: - Corrections
public func disableDefaultPhpFpmPool(_ version: String) async -> FixApplied {
let pool = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf"
let pool = "\(App.shared.container.paths.etcPath)/php/\(version)/php-fpm.d/www.conf"
if App.shared.container.filesystem.fileExists(pool) {
Log.info("A default `www.conf` file was found in the php-fpm.d directory for PHP \(version).")
let existing = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf"
let new = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf.disabled-by-phpmon"
let existing = "\(App.shared.container.paths.etcPath)/php/\(version)/php-fpm.d/www.conf"
let new = "\(App.shared.container.paths.etcPath)/php/\(version)/php-fpm.d/www.conf.disabled-by-phpmon"
do {
if App.shared.container.filesystem.fileExists(new) {
Log.info("A moved `www.conf.disabled-by-phpmon` file was found for PHP \(version), "
@@ -59,7 +59,7 @@ extension InternalSwitcher {
// For each of the files, attempt to fix anything that is wrong
let outcomes = files.map { file in
let configFileExists = App.shared.container.filesystem.fileExists("\(Paths.etcPath)/php/\(version)/" + file.destination)
let configFileExists = App.shared.container.filesystem.fileExists("\(App.shared.container.paths.etcPath)/php/\(version)/" + file.destination)
if configFileExists {
return false
@@ -79,7 +79,7 @@ extension InternalSwitcher {
}
try App.shared.container.filesystem.writeAtomicallyToFile(
"\(Paths.etcPath)/php/\(version)" + file.destination,
"\(App.shared.container.paths.etcPath)/php/\(version)" + file.destination,
content: contents
)
} catch {
@@ -102,7 +102,7 @@ extension InternalSwitcher {
destination: "/php-fpm.d/valet-fpm.conf",
source: "/cli/stubs/etc-phpfpm-valet.conf",
replacements: [
"VALET_USER": Paths.whoami,
"VALET_USER": App.shared.container.paths.whoami,
"VALET_HOME_PATH": "~/.config/valet".replacingTildeWithHomeDirectory,
"valet.sock": "valet\(version.replacingOccurrences(of: ".", with: "")).sock"
],
@@ -112,7 +112,7 @@ extension InternalSwitcher {
destination: "/conf.d/error_log.ini",
source: "/cli/stubs/etc-phpfpm-error_log.ini",
replacements: [
"VALET_USER": Paths.whoami,
"VALET_USER": App.shared.container.paths.whoami,
"VALET_HOME_PATH": "~/.config/valet".replacingTildeWithHomeDirectory
],
applies: { return true }

View File

@@ -10,6 +10,6 @@ import Foundation
protocol CreatedFromFile {
static func from(filePath: String) -> Self?
static func from(filePath: String, container: Container) -> Self?
}

View File

@@ -59,7 +59,7 @@ class RealShell: ShellProtocol {
var completeCommand = ""
// Basic export (PATH)
completeCommand += "export PATH=\(Paths.binPath):$PATH && "
completeCommand += "export PATH=\(container.paths.binPath):$PATH && "
// Put additional exports (as defined by the user) in between
if !self.exports.isEmpty {

View File

@@ -10,6 +10,7 @@ class Container {
var shell: ShellProtocol!
var filesystem: FileSystemProtocol!
var command: CommandProtocol!
var paths: Paths!
var favorites: Favorites!
var warningManager: WarningManager!
@@ -20,6 +21,7 @@ class Container {
self.shell = RealShell(container: self)
self.filesystem = RealFileSystem(container: self)
self.command = RealCommand()
self.paths = Paths(container: self)
self.favorites = Favorites()
self.warningManager = WarningManager(container: self)

View File

@@ -23,12 +23,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
*/
let state: App
/**
The paths singleton that determines where Homebrew is installed,
and where to look for binaries.
*/
let paths: Paths
/**
The Valet singleton that determines all information
about Valet and its current configuration.
@@ -93,7 +87,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
Log.separator(as: .info)
}
self.paths = Paths.shared
self.valet = Valet.shared
self.brew = Brew.shared
super.init()

View File

@@ -166,7 +166,7 @@ class AppUpdater {
}
private func cleanupCaskroom() {
let path = Paths.caskroomPath
let path = App.shared.container.paths.caskroomPath
if App.shared.container.filesystem.directoryExists(path) {
Log.info("Removing the Caskroom directory for PHP Monitor...")

View File

@@ -48,7 +48,7 @@ class ValetServicesManager: ServicesManager {
.map { $0.name }
let rootJson = await App.shared.container.shell
.pipe("sudo \(Paths.brew) services info --all --json")
.pipe("sudo \(App.shared.container.paths.brew) services info --all --json")
.out.data(using: .utf8)!
return try! JSONDecoder()
@@ -63,7 +63,7 @@ class ValetServicesManager: ServicesManager {
.map { $0.name }
let normalJson = await App.shared.container.shell
.pipe("\(Paths.brew) services info --all --json")
.pipe("\(App.shared.container.paths.brew) services info --all --json")
.out.data(using: .utf8)!
return try! JSONDecoder()

View File

@@ -101,15 +101,15 @@ class Startup {
// The Homebrew binary must exist.
// =================================================================================
EnvironmentCheck(
command: { return !App.shared.container.filesystem.fileExists(Paths.brew) },
name: "`\(Paths.brew)` exists",
command: { return !App.shared.container.filesystem.fileExists(App.shared.container.paths.brew) },
name: "`\(App.shared.container.paths.brew)` exists",
titleText: "alert.homebrew_missing.title".localized,
subtitleText: "alert.homebrew_missing.subtitle".localized,
descriptionText: "alert.homebrew_missing.info".localized(
App.architecture
.replacingOccurrences(of: "x86_64", with: "Intel")
.replacingOccurrences(of: "arm64", with: "Apple Silicon"),
Paths.brew
App.shared.container.paths.brew
),
buttonText: "alert.homebrew_missing.quit".localized,
requiresAppRestart: true
@@ -119,12 +119,12 @@ class Startup {
// =================================================================================
EnvironmentCheck(
command: {
return await !App.shared.container.shell.pipe("ls \(Paths.optPath) | grep php").out.contains("php")
return await !App.shared.container.shell.pipe("ls \(App.shared.container.paths.optPath) | grep php").out.contains("php")
},
name: "`ls \(Paths.optPath) | grep php` returned php result",
name: "`ls \(App.shared.container.paths.optPath) | grep php` returned php result",
titleText: "startup.errors.php_opt.title".localized,
subtitleText: "startup.errors.php_opt.subtitle".localized(
Paths.optPath
App.shared.container.paths.optPath
),
descriptionText: "startup.errors.php_opt.desc".localized
)
@@ -134,24 +134,24 @@ class Startup {
// The PHP binary must exist.
// =================================================================================
EnvironmentCheck(
command: { return !App.shared.container.filesystem.fileExists(Paths.php) },
name: "`\(Paths.php)` exists",
command: { return !App.shared.container.filesystem.fileExists(App.shared.container.paths.php) },
name: "`\(App.shared.container.paths.php)` exists",
titleText: "startup.errors.php_binary.title".localized,
subtitleText: "startup.errors.php_binary.subtitle".localized,
descriptionText: "startup.errors.php_binary.desc".localized(Paths.php)
descriptionText: "startup.errors.php_binary.desc".localized(App.shared.container.paths.php)
),
// =================================================================================
// Ensure that the main PHP installation is not broken.
// =================================================================================
EnvironmentCheck(
command: {
return await App.shared.container.shell.pipe("\(Paths.binPath)/php -v").err
return await App.shared.container.shell.pipe("\(App.shared.container.paths.binPath)/php -v").err
.contains("Library not loaded")
},
name: "no `dyld` issue (`Library not loaded`) detected",
titleText: "startup.errors.dyld_library.title".localized,
subtitleText: "startup.errors.dyld_library.subtitle".localized(
Paths.optPath
App.shared.container.paths.optPath
),
descriptionText: "startup.errors.dyld_library.desc".localized
),
@@ -160,14 +160,14 @@ class Startup {
// =================================================================================
EnvironmentCheck(
command: {
return !(App.shared.container.filesystem.fileExists(Paths.valet)
return !(App.shared.container.filesystem.fileExists(App.shared.container.paths.valet)
|| App.shared.container.filesystem.fileExists("~/.composer/vendor/bin/valet"))
},
name: "`valet` binary exists",
titleText: "startup.errors.valet_executable.title".localized,
subtitleText: "startup.errors.valet_executable.subtitle".localized,
descriptionText: "startup.errors.valet_executable.desc".localized(
Paths.valet
App.shared.container.paths.valet
)
),
// =================================================================================
@@ -176,14 +176,14 @@ class Startup {
// functioning correctly. Let the user know that they need to run `valet trust`.
// =================================================================================
EnvironmentCheck(
command: { return await !App.shared.container.shell.pipe("cat /private/etc/sudoers.d/brew").out.contains(Paths.brew) },
command: { return await !App.shared.container.shell.pipe("cat /private/etc/sudoers.d/brew").out.contains(App.shared.container.paths.brew) },
name: "`/private/etc/sudoers.d/brew` contains brew",
titleText: "startup.errors.sudoers_brew.title".localized,
subtitleText: "startup.errors.sudoers_brew.subtitle".localized,
descriptionText: "startup.errors.sudoers_brew.desc".localized
),
EnvironmentCheck(
command: { return await !App.shared.container.shell.pipe("cat /private/etc/sudoers.d/valet").out.contains(Paths.valet) },
command: { return await !App.shared.container.shell.pipe("cat /private/etc/sudoers.d/valet").out.contains(App.shared.container.paths.valet) },
name: "`/private/etc/sudoers.d/valet` contains valet",
titleText: "startup.errors.sudoers_valet.title".localized,
subtitleText: "startup.errors.sudoers_valet.subtitle".localized,
@@ -207,7 +207,7 @@ class Startup {
EnvironmentCheck(
command: {
// Detect additional binaries (e.g. Composer)
Paths.shared.detectBinaryPaths()
App.shared.container.paths.detectBinaryPaths()
// Load the configuration file (config.json)
Valet.shared.loadConfiguration()
// This check fails when the config is nil
@@ -226,7 +226,7 @@ class Startup {
await BrewDiagnostics.shared.loadInstalledTaps()
return await BrewDiagnostics.shared.cannotLoadService("dnsmasq")
},
name: "`sudo \(Paths.brew) services info` JSON loaded",
name: "`sudo \(App.shared.container.paths.brew) services info` JSON loaded",
titleText: "startup.errors.services_json_error.title".localized,
subtitleText: "startup.errors.services_json_error.subtitle".localized,
descriptionText: "startup.errors.services_json_error.desc".localized

View File

@@ -22,9 +22,9 @@ import ContainerMacro
self.shouldNotify = notify
self.completion = completion
Paths.shared.detectBinaryPaths()
container.paths.detectBinaryPaths()
if Paths.composer == nil {
if container.paths.composer == nil {
self.presentMissingAlert()
return
}
@@ -52,7 +52,7 @@ import ContainerMacro
}
private func runComposerUpdateShellCommand() async throws {
let command = "\(Paths.composer!) global update"
let command = "\(container.paths.composer!) global update"
self.window?.addToConsole("\(command)\n")

View File

@@ -7,9 +7,10 @@
//
import Foundation
import ContainerMacro
@ContainerAccess
class BrewPermissionFixer {
var broken: [DueOwnershipFormula] = []
/**
@@ -61,8 +62,8 @@ class BrewPermissionFixer {
? "php"
: "php@\(formula)"
let binFolderOwned = isOwnedByRoot(path: "\(Paths.optPath)/\(realFormula)/bin")
let sbinFolderOwned = isOwnedByRoot(path: "\(Paths.optPath)/\(realFormula)/sbin")
let binFolderOwned = isOwnedByRoot(path: "\(container.paths.optPath)/\(realFormula)/bin")
let sbinFolderOwned = isOwnedByRoot(path: "\(container.paths.optPath)/\(realFormula)/sbin")
if binFolderOwned || sbinFolderOwned {
Log.warn("\(formula) is owned by root")
@@ -70,14 +71,14 @@ class BrewPermissionFixer {
if binFolderOwned {
broken.append(DueOwnershipFormula(
formula: realFormula,
path: "\(Paths.optPath)/\(realFormula)/bin"
path: "\(container.paths.optPath)/\(realFormula)/bin"
))
}
if sbinFolderOwned {
broken.append(DueOwnershipFormula(
formula: realFormula,
path: "\(Paths.optPath)/\(realFormula)/sbin"
path: "\(container.paths.optPath)/\(realFormula)/sbin"
))
}
}
@@ -92,8 +93,8 @@ class BrewPermissionFixer {
return broken
.map { b in
return """
\(Paths.brew) services stop \(b.formula) \
&& chown -R \(Paths.whoami):admin \(b.path)
\(container.paths.brew) services stop \(b.formula) \
&& chown -R \(container.paths.whoami):admin \(b.path)
"""
}
.joined(

View File

@@ -21,7 +21,7 @@ class Brew {
/// Determine which version of Homebrew is installed.
public func determineVersion() async {
let output = await shell.pipe("\(Paths.brew) --version")
let output = await shell.pipe("\(container.paths.brew) --version")
self.version = try? VersionNumber.parse(output.out)
if let version = version {

View File

@@ -24,7 +24,7 @@ class BrewDiagnostics {
*/
public func loadInstalledTaps() async {
installedTaps = await shell
.pipe("\(Paths.brew) tap")
.pipe("\(container.paths.brew) tap")
.out
.split(separator: "\n")
.map { string in
@@ -52,14 +52,14 @@ class BrewDiagnostics {
*/
public var customCaskInstalled: Bool {
return installedTaps.contains("nicoverbruggen/cask")
&& filesystem.directoryExists(Paths.caskroomPath)
&& filesystem.directoryExists(container.paths.caskroomPath)
}
/**
Determines whether to use the regular `nginx` or `nginx-full` formula.
*/
public var usesNginxFullFormula: Bool {
guard let destination = try? filesystem.getDestinationOfSymlink("\(Paths.binPath)/nginx") else { return false }
guard let destination = try? filesystem.getDestinationOfSymlink("\(container.paths.binPath)/nginx") else { return false }
// Verify that the `nginx` binary is symlinked to a directory that includes `nginx-full`.
return destination.contains("/nginx-full/")
@@ -76,7 +76,7 @@ class BrewDiagnostics {
let regex = try! NSRegularExpression(pattern: "^php@[0-9]+\\.[0-9]+$", options: .caseInsensitive)
// Check for incorrect versions
if let contents = try? filesystem.getShallowContentsOfDirectory("\(Paths.optPath)")
if let contents = try? filesystem.getShallowContentsOfDirectory("\(container.paths.optPath)")
.filter({
let range = NSRange($0.startIndex..., in: $0)
return regex.firstMatch(in: $0, options: [], range: range) != nil
@@ -84,19 +84,19 @@ class BrewDiagnostics {
for symlink in contents {
let version = symlink.replacingOccurrences(of: "php@", with: "")
if let destination = try? filesystem.getDestinationOfSymlink("\(Paths.optPath)/\(symlink)") {
if let destination = try? filesystem.getDestinationOfSymlink("\(container.paths.optPath)/\(symlink)") {
if !destination.contains("Cellar/php/\(version)")
&& !destination.contains("Cellar/php@\(version)") {
Log.err("Symlink for \(symlink) is incorrect. Removing...")
do {
try filesystem.remove("\(Paths.optPath)/\(symlink)")
try filesystem.remove("\(container.paths.optPath)/\(symlink)")
Log.info("Incorrect symlink for \(symlink) has been successfully removed.")
} catch {
Log.err("Symlink for \(symlink) was incorrect but could not be removed!")
}
}
} else {
Log.warn("Could not read symlink at: \(Paths.optPath)/\(symlink)! Symlink check skipped.")
Log.warn("Could not read symlink at: \(container.paths.optPath)/\(symlink)! Symlink check skipped.")
}
}
}
@@ -219,7 +219,7 @@ class BrewDiagnostics {
*/
public func cannotLoadService(_ name: String) async -> Bool {
let nginxJson = await shell
.pipe("sudo \(Paths.brew) services info \(name) --json")
.pipe("sudo \(container.paths.brew) services info \(name) --json")
.out
let serviceInfo = try? JSONDecoder().decode(

View File

@@ -59,7 +59,7 @@ struct BrewPhpExtension: Hashable, Comparable {
}
static func hasInstallationReceipt(for formulaName: String) -> Bool {
return App.shared.container.filesystem.fileExists("\(Paths.optPath)/\(formulaName)/INSTALL_RECEIPT.json")
return App.shared.container.filesystem.fileExists("\(App.shared.container.paths.optPath)/\(formulaName)/INSTALL_RECEIPT.json")
}
static func < (lhs: BrewPhpExtension, rhs: BrewPhpExtension) -> Bool {

View File

@@ -77,7 +77,7 @@ struct BrewPhpFormula: Equatable {
.replacingOccurrences(of: "shivammathur/php/", with: "")
.replacingOccurrences(of: "php@" + PhpEnvironments.brewPhpAlias, with: "php")
return "\(Paths.optPath)/\(resolved)/bin"
return "\(App.shared.container.paths.optPath)/\(resolved)/bin"
}
/// The short version associated with this formula, if installed.
@@ -105,7 +105,7 @@ struct BrewPhpFormula: Equatable {
}
return App.shared.container.filesystem.fileExists(
"\(Paths.tapPath)/shivammathur/homebrew-php/Formula/php@\(version).rb"
"\(App.shared.container.paths.tapPath)/shivammathur/homebrew-php/Formula/php@\(version).rb"
.replacingOccurrences(of: "php@" + PhpEnvironments.brewPhpAlias, with: "php")
)
}

View File

@@ -31,8 +31,8 @@ class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae {
if loadOutdated {
let command = """
\(Paths.brew) update >/dev/null && \
\(Paths.brew) outdated --json --formulae
\(container.paths.brew) update >/dev/null && \
\(container.paths.brew) outdated --json --formulae
"""
let rawJsonText = await shell.pipe(command).out

View File

@@ -10,7 +10,7 @@ import Foundation
class BrewTapFormulae {
public static func from(tap: String) -> [String: [BrewPhpExtension]] {
let directory = "\(Paths.tapPath)/\(tap)/Formula"
let directory = "\(App.shared.container.paths.tapPath)/\(tap)/Formula"
let files = try? App.shared.container.filesystem.getShallowContentsOfDirectory(directory)
@@ -35,7 +35,7 @@ class BrewTapFormulae {
// Create a new BrewPhpExtension object (determines if installed)
let phpExtension = BrewPhpExtension(
path: "\(Paths.tapPath)/\(tap)/Formula/\(file)",
path: "\(App.shared.container.paths.tapPath)/\(tap)/Formula/\(file)",
name: phpExtensionName,
phpVersion: phpVersion
)

View File

@@ -56,7 +56,7 @@ class InstallPhpExtensionCommand: BrewCommand {
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
\(Paths.brew) install \(self.installing.map { $0.formulaName }.joined(separator: " ")) --force
\(container.paths.brew) install \(self.installing.map { $0.formulaName }.joined(separator: " ")) --force
"""
try await run(shell: shell, command, onProgress)
@@ -68,7 +68,7 @@ class InstallPhpExtensionCommand: BrewCommand {
// Restart PHP-FPM
if let installed = self.installing.first {
await Actions.restartPhpFpm(version: installed.phpVersion)
await Actions().restartPhpFpm(version: installed.phpVersion)
}
// Check which version of PHP are now installed

View File

@@ -41,7 +41,7 @@ class RemovePhpExtensionCommand: BrewCommand {
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
\(Paths.brew) remove \(phpExtension.formulaName) --force --ignore-dependencies
\(container.paths.brew) remove \(phpExtension.formulaName) --force --ignore-dependencies
"""
var loggedMessages: [String] = []
@@ -66,7 +66,7 @@ class RemovePhpExtensionCommand: BrewCommand {
await PhpEnvironments.detectPhpVersions()
await Actions.restartPhpFpm(version: phpExtension.phpVersion)
await Actions().restartPhpFpm(version: phpExtension.phpVersion)
await MainMenu.shared.refreshActiveInstallation()

View File

@@ -98,8 +98,8 @@ class ModifyPhpVersionCommand: BrewCommand {
let command = """
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
\(Paths.brew) upgrade php;
\(Paths.brew) install php@\(short);
\(container.paths.brew) upgrade php;
\(container.paths.brew) install php@\(short);
"""
// Run the upgrade command
@@ -116,7 +116,7 @@ class ModifyPhpVersionCommand: BrewCommand {
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
\(Paths.brew) upgrade \(self.upgrading.map { $0.name }.joined(separator: " "))
\(container.paths.brew) upgrade \(self.upgrading.map { $0.name }.joined(separator: " "))
"""
try await run(shell: shell, command, onProgress)
@@ -131,7 +131,7 @@ class ModifyPhpVersionCommand: BrewCommand {
let command = """
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
\(Paths.brew) install \(self.installing.map { $0.name }.joined(separator: " ")) --force
\(container.paths.brew) install \(self.installing.map { $0.name }.joined(separator: " ")) --force
"""
try await run(shell: shell, command, onProgress)
@@ -163,7 +163,7 @@ class ModifyPhpVersionCommand: BrewCommand {
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=true; \
\(Paths.brew) reinstall \(requiringRepair.joined(separator: " ")) --force
\(container.paths.brew) reinstall \(requiringRepair.joined(separator: " ")) --force
"""
try await run(shell: shell, command, onProgress)

View File

@@ -39,7 +39,7 @@ class RemovePhpVersionCommand: BrewCommand {
export HOMEBREW_DOWNLOAD_CONCURRENCY=auto; \
export HOMEBREW_NO_INSTALL_UPGRADE=true; \
export HOMEBREW_NO_INSTALL_CLEANUP=true; \
\(Paths.brew) remove \(formula) --force --ignore-dependencies
\(container.paths.brew) remove \(formula) --force --ignore-dependencies
"""
do {

View File

@@ -20,8 +20,11 @@ class NginxConfigurationFile: CreatedFromFile {
var tld: String
/** Resolves an nginx configuration file (.conf) */
static func from(filePath: String) -> Self? {
let path = filePath.replacingOccurrences(of: "~", with: Paths.homePath)
static func from(
filePath: String,
container: Container = App.shared.container
) -> Self? {
let path = filePath.replacingOccurrences(of: "~", with: container.paths.homePath)
do {
let fileContents = try String(contentsOfFile: path)

View File

@@ -25,7 +25,7 @@ class ValetInteractor {
// MARK: - Managing Domains
public func link(path: String, domain: String) async throws {
await shell.quiet("cd '\(path)' && \(Paths.valet) link '\(domain)' && valet links")
await shell.quiet("cd '\(path)' && \(container.paths.valet) link '\(domain)' && valet links")
}
public func unlink(site: ValetSite) async throws {
@@ -34,11 +34,11 @@ class ValetInteractor {
public func proxy(domain: String, proxy: String, secure: Bool) async throws {
let command = secure
? "\(Paths.valet) proxy \(domain) \(proxy) --secure"
: "\(Paths.valet) proxy \(domain) \(proxy)"
? "\(container.paths.valet) proxy \(domain) \(proxy) --secure"
: "\(container.paths.valet) proxy \(domain) \(proxy)"
await shell.quiet(command)
await Actions.restartNginx()
await Actions().restartNginx()
}
public func remove(proxy: ValetProxy) async throws {
@@ -56,11 +56,11 @@ class ValetInteractor {
// Use modernized version of command using domain name
// This will allow us to secure multiple domains that use the same path
var command = "sudo \(Paths.valet) \(action) '\(site.name)' && exit;"
var command = "sudo \(container.paths.valet) \(action) '\(site.name)' && exit;"
// For Valet 2, use the old syntax; this has a known issue so Valet 3+ is preferred
if !Valet.enabled(feature: .isolatedSites) {
command = "cd '\(site.absolutePath)' && sudo \(Paths.valet) \(action) && exit;"
command = "cd '\(site.absolutePath)' && sudo \(container.paths.valet) \(action) && exit;"
}
// Run the command
@@ -80,11 +80,11 @@ class ValetInteractor {
// Build the list of commands we will need to run
let commands: [String] = [
// Unproxy the given domain
"\(Paths.valet) unproxy \(proxy.domain)",
"\(container.paths.valet) unproxy \(proxy.domain)",
// Re-create the proxy (with the inverse secured status)
originalSecureStatus
? "\(Paths.valet) proxy \(proxy.domain) \(proxy.target)"
: "\(Paths.valet) proxy \(proxy.domain) \(proxy.target) --secure"
? "\(container.paths.valet) proxy \(proxy.domain) \(proxy.target)"
: "\(container.paths.valet) proxy \(proxy.domain) \(proxy.target) --secure"
]
// Run the commands
@@ -101,11 +101,11 @@ class ValetInteractor {
}
// Restart nginx to load the new configuration
await Actions.restartNginx()
await Actions().restartNginx()
}
public func isolate(site: ValetSite, version: String) async throws {
let command = "sudo \(Paths.valet) isolate php@\(version) --site '\(site.name)'"
let command = "sudo \(container.paths.valet) isolate php@\(version) --site '\(site.name)'"
// Run the command
await shell.quiet(command)
@@ -121,7 +121,7 @@ class ValetInteractor {
}
public func unisolate(site: ValetSite) async throws {
let command = "sudo \(Paths.valet) unisolate --site '\(site.name)'"
let command = "sudo \(container.paths.valet) unisolate --site '\(site.name)'"
// Run the command
await shell.quiet(command)

View File

@@ -21,7 +21,7 @@ class ValetSite: ValetListable {
/// replacing the user's home folder with ~.
lazy var absolutePathRelative: String = {
return self.absolutePath
.replacingOccurrences(of: Paths.homePath, with: "~")
.replacingOccurrences(of: container.paths.homePath, with: "~")
}()
/// The TLD used to locate this site.

View File

@@ -68,7 +68,7 @@ class Valet {
}
lazy var installed: Bool = {
return filesystem.fileExists(Paths.binPath.appending("/valet"))
return filesystem.fileExists(container.paths.binPath.appending("/valet"))
&& filesystem.anyExists("~/.config/valet")
}()
@@ -250,13 +250,13 @@ class Valet {
if version.short == "5.6" {
// The main PHP config file should contain `valet.sock` and then we're probably fine?
let fileName = "\(Paths.etcPath)/php/5.6/php-fpm.conf"
let fileName = "\(container.paths.etcPath)/php/5.6/php-fpm.conf"
return await shell.pipe("cat \(fileName)").out
.contains("valet.sock")
}
// Make sure to check if valet-fpm.conf exists. If it does, we should be fine :)
return filesystem.fileExists("\(Paths.etcPath)/php/\(version.short)/php-fpm.d/valet-fpm.conf")
return filesystem.fileExists("\(container.paths.etcPath)/php/\(version.short)/php-fpm.d/valet-fpm.conf")
}
/**

View File

@@ -15,7 +15,7 @@ extension MainMenu {
@MainActor @objc func linkPhpBinary() {
Task {
await Actions.linkPhp()
await Actions().linkPhp()
}
}
@@ -46,7 +46,7 @@ extension MainMenu {
}
asyncExecution {
try Actions.fixHomebrewPermissions()
try Actions().fixHomebrewPermissions()
} success: {
NVAlert()
.withInformation(
@@ -63,27 +63,27 @@ extension MainMenu {
@objc func restartPhpFpm() {
Task { // Simple restart service
await Actions.restartPhpFpm()
await Actions().restartPhpFpm()
}
}
@objc func restartNginx() {
Task { // Simple restart service
await Actions.restartNginx()
await Actions().restartNginx()
}
}
@objc func restartDnsMasq() {
Task { // Simple restart service
await Actions.restartDnsMasq()
await Actions().restartDnsMasq()
}
}
@MainActor @objc func restartValetServices() {
Task { // Restart services and show notification
await Actions.restartDnsMasq()
await Actions.restartPhpFpm()
await Actions.restartNginx()
await Actions().restartDnsMasq()
await Actions().restartPhpFpm()
await Actions().restartNginx()
LocalNotification.send(
title: "notification.services_restarted".localized,
@@ -95,7 +95,7 @@ extension MainMenu {
@MainActor @objc func stopValetServices() {
Task { // Stop services and show notification
await Actions.stopValetServices()
await Actions().stopValetServices()
LocalNotification.send(
title: "notification.services_stopped".localized,
@@ -158,7 +158,7 @@ extension MainMenu {
await sender.phpExtension?.toggle()
if Preferences.isEnabled(.autoServiceRestartAfterExtensionToggle) {
await Actions.restartPhpFpm()
await Actions().restartPhpFpm()
}
}
}
@@ -233,23 +233,23 @@ extension MainMenu {
}
if install.hasErrorState {
Actions.openGenericPhpConfigFolder()
Actions().openGenericPhpConfigFolder()
return
}
Actions.openPhpConfigFolder(version: install.version.short)
Actions().openPhpConfigFolder(version: install.version.short)
}
@objc func openPhpMonitorConfigurationFile() {
Actions.openPhpMonitorConfigFile()
Actions().openPhpMonitorConfigFile()
}
@objc func openGlobalComposerFolder() {
Actions.openGlobalComposerFolder()
Actions().openGlobalComposerFolder()
}
@objc func openValetConfigFolder() {
Actions.openValetConfigFolder()
Actions().openValetConfigFolder()
}
@objc func switchToPhpVersion(sender: PhpMenuItem) {

View File

@@ -33,7 +33,7 @@ extension MainMenu {
}
Task { @MainActor in
await Actions.fixMyValet()
await Actions().fixMyValet()
if previousVersion == PhpEnvironments.brewPhpAlias || previousVersion == nil {
self.presentAlertForSameVersion()

View File

@@ -51,7 +51,7 @@ extension Preferences {
await moveOutdatedConfigurationFile()
// Attempt to load the file if it exists
let url = URL(fileURLWithPath: "\(Paths.homePath)/.config/phpmon/config.json")
let url = URL(fileURLWithPath: "\(App.shared.container.paths.homePath)/.config/phpmon/config.json")
if App.shared.container.filesystem.fileExists(url.path) {
Log.info("A custom ~/.config/phpmon/config.json file was found. Attempting to parse...")

View File

@@ -79,7 +79,7 @@ struct Preset: Codable, Equatable {
if self.version != nil {
if await !switchToPhpVersionIfValid() {
PresetHelper.rollbackPreset = nil
await Actions.restartPhpFpm()
await Actions().restartPhpFpm()
return
}
}
@@ -107,7 +107,7 @@ struct Preset: Codable, Equatable {
PresetHelper.loadRollbackPresetFromFile()
// Restart PHP FPM process (also reloads menu, which will show the preset rollback)
await Actions.restartPhpFpm()
await Actions().restartPhpFpm()
Task { @MainActor in
// Show the correct notification
@@ -276,7 +276,7 @@ struct Preset: Codable, Equatable {
try! String(data: data, encoding: .utf8)!
.write(
toFile: "\(Paths.homePath)/.config/phpmon/preset_revert.json",
toFile: "\(App.shared.container.paths.homePath)/.config/phpmon/preset_revert.json",
atomically: true,
encoding: .utf8
)

View File

@@ -16,7 +16,7 @@ class PresetHelper {
public static func loadRollbackPresetFromFile() {
guard let revert = try? String(
contentsOfFile: "\(Paths.homePath)/.config/phpmon/preset_revert.json",
contentsOfFile: "\(App.shared.container.paths.homePath)/.config/phpmon/preset_revert.json",
encoding: .utf8
) else {
PresetHelper.rollbackPreset = nil

View File

@@ -12,7 +12,7 @@ extension App {
public func prepareHomebrewWatchers() {
let notifier = FSNotifier(
for: URL(fileURLWithPath: Paths.binPath),
for: URL(fileURLWithPath: container.paths.binPath),
eventMask: .all,
onChange: { Task { await self.onHomebrewPhpModification() } }
)

View File

@@ -39,7 +39,7 @@ extension App {
return
}
let url = URL(fileURLWithPath: "\(Paths.etcPath)/php/\(install.version.short)")
let url = URL(fileURLWithPath: "\(container.paths.etcPath)/php/\(install.version.short)")
// Check whether the manager exists and schedule on the main thread
// if we don't consistently do this, the app will create duplicate watchers

View File

@@ -142,7 +142,7 @@ extension DomainListVC {
await sender.phpExtension?.toggle()
if Preferences.isEnabled(.autoServiceRestartAfterExtensionToggle) {
await Actions.restartPhpFpm()
await Actions().restartPhpFpm()
}
reloadContextMenu()

View File

@@ -38,7 +38,7 @@ class BytePhpPreference: PhpPreference {
override init(container: Container = App.shared.container, key: String) {
let value = container.command.execute(
path: Paths.php, arguments: ["-r", "echo ini_get('\(key)');"],
path: container.paths.php, arguments: ["-r", "echo ini_get('\(key)');"],
trimNewlines: false
)

View File

@@ -35,7 +35,7 @@ class PhpConfigChecker {
}
// Do the check
let fullFilePath = Paths.etcPath.appending("/php/\(version)/\(file.path)")
let fullFilePath = App.shared.container.paths.etcPath.appending("/php/\(version)/\(file.path)")
if !App.shared.container.filesystem.fileExists(fullFilePath) {
missing.append(fullFilePath)
}

View File

@@ -23,7 +23,7 @@ extension WarningManager {
),
Warning(
command: {
return !App.shared.container.shell.PATH.contains("\(Paths.homePath)/.config/phpmon/bin") &&
return !App.shared.container.shell.PATH.contains("\(App.shared.container.paths.homePath)/.config/phpmon/bin") &&
!App.shared.container.filesystem.isWriteableFile("/usr/local/bin/")
},
name: "Helpers cannot be symlinked and not in PATH",
@@ -34,7 +34,7 @@ extension WarningManager {
"warnings.helper_permissions.symlink"
] },
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries",
fix: Paths.shell == "/bin/zsh" ? {
fix: App.shared.container.paths.shell == "/bin/zsh" ? {
// Add to PATH
await ZshRunCommand().addPhpMonitorPath()
// Finally, perform environment checks again