1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-12-21 03:10:06 +01:00

♻️ Update ContainerAccess macro

This commit is contained in:
2025-10-16 18:58:10 +02:00
parent fa403b5a99
commit 65223f348b
44 changed files with 171 additions and 149 deletions

View File

@@ -1422,6 +1422,15 @@
path = Provision; path = Provision;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
03C099422EA156C100B76D43 /* Container */ = {
isa = PBXGroup;
children = (
0329A9A02E92A2A800A62A12 /* Container.swift */,
031F247F2EA1071700CFB8D9 /* Container+Fake.swift */,
);
path = Container;
sourceTree = "<group>";
};
03D53E902E8AE089001B1671 /* Testables */ = { 03D53E902E8AE089001B1671 /* Testables */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -1615,8 +1624,7 @@
C41C1B3522B0097F00E7CF16 /* phpmon */ = { C41C1B3522B0097F00E7CF16 /* phpmon */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
031F247F2EA1071700CFB8D9 /* Container+Fake.swift */, 03C099422EA156C100B76D43 /* Container */,
0329A9A02E92A2A800A62A12 /* Container.swift */,
C4B5853A2770FE2500DA4FBE /* Common */, C4B5853A2770FE2500DA4FBE /* Common */,
C41E181722CB61EB0072CF09 /* Domain */, C41E181722CB61EB0072CF09 /* Domain */,
54D9E0BE27E4F5C0003B9AD9 /* Vendor */, 54D9E0BE27E4F5C0003B9AD9 /* Vendor */,

View File

@@ -30,7 +30,7 @@
codeCoverageEnabled = "YES"> codeCoverageEnabled = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
skipped = "NO" skipped = "YES"
parallelizable = "NO" parallelizable = "NO"
testExecutionOrdering = "random"> testExecutionOrdering = "random">
<BuildableReference <BuildableReference
@@ -53,7 +53,7 @@
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
<TestableReference <TestableReference
skipped = "NO" skipped = "YES"
parallelizable = "NO"> parallelizable = "NO">
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"

View File

@@ -10,9 +10,8 @@ import ContainerMacro
@ContainerAccess @ContainerAccess
class MyClass { class MyClass {
func doSomething() { func doSomething() {
shell.run("command") container.shell.run("command")
favorites.add(site) container.favorites.add(site)
warningManager.evaluateWarnings()
} }
} }
``` ```
@@ -21,7 +20,7 @@ class MyClass {
The `@ContainerAccess` macro automatically adds: The `@ContainerAccess` macro automatically adds:
- A private `container: Container` property - A private `container: Container` property
- An `init(container:)` with default parameter `App.shared.container` - An `init(_ container:)` initializer
- Computed properties for each Container service you want to access - Computed properties for each Container service you want to access
## Maintenance ## Maintenance
@@ -33,8 +32,6 @@ When you add new services to `Container`, you must update the service list in:
```swift ```swift
let allContainerServices: [(name: String, type: String)] = [ let allContainerServices: [(name: String, type: String)] = [
("shell", "ShellProtocol"), ("shell", "ShellProtocol"),
("favorites", "Favorites"),
("warningManager", "WarningManager"),
// Add your new service here: // Add your new service here:
// ("myNewService", "MyServiceType"), // ("myNewService", "MyServiceType"),
] ]

View File

@@ -2,7 +2,7 @@
/// ///
/// This macro generates: /// This macro generates:
/// - A public `container` property /// - A public `container` property
/// - An `init(container:)` with a default parameter of `App.shared.container` (only if no init exists) /// - An `init(_ container:)` initializer
/// - Computed properties for all Container services /// - Computed properties for all Container services
/// ///
/// Usage: /// Usage:
@@ -12,9 +12,8 @@
/// @ContainerAccess /// @ContainerAccess
/// class MyClass { /// class MyClass {
/// func doSomething() { /// func doSomething() {
/// shell.run("command") /// container.shell.run("command")
/// favorites.add(site) /// container.favorites.add(site)
/// warningManager.evaluateWarnings()
/// } /// }
/// } /// }
/// ``` /// ```

View File

@@ -42,24 +42,13 @@ public struct ContainerAccessMacro: MemberMacro {
if !hasExistingInit { if !hasExistingInit {
members.append( members.append(
""" """
init(container: Container = App.shared.container) { init(_ container: Container) {
self.container = container self.container = container
} }
""" """
) )
} }
// Add computed properties for each service
for service in allContainerServices {
members.append(
"""
private var \(raw: service.name): \(raw: service.type) {
return container.\(raw: service.name)
}
"""
)
}
return members return members
} }
} }

View File

@@ -8,7 +8,6 @@
import Cocoa import Cocoa
public class RealCommand: CommandProtocol { public class RealCommand: CommandProtocol {
public func execute( public func execute(
path: String, path: String,
arguments: [String], arguments: [String],
@@ -52,5 +51,4 @@ public class RealCommand: CommandProtocol {
withStandardError: false withStandardError: false
) )
} }
} }

View File

@@ -12,7 +12,11 @@ import ContainerMacro
@ContainerAccess @ContainerAccess
class Actions { class Actions {
var formulae: HomebrewFormulae { var formulae: HomebrewFormulae {
return HomebrewFormulae() return HomebrewFormulae(App.shared.container)
}
var paths: Paths {
return container.paths
} }
// MARK: - Services // MARK: - Services
@@ -110,10 +114,10 @@ class Actions {
// MARK: - Other Actions // MARK: - Other Actions
public func createTempPhpInfoFile() async -> URL { public func createTempPhpInfoFile() async -> URL {
try! filesystem.writeAtomicallyToFile("/tmp/phpmon_phpinfo.php", content: "<?php phpinfo();") try! container.filesystem.writeAtomicallyToFile("/tmp/phpmon_phpinfo.php", content: "<?php phpinfo();")
// Tell php-cgi to run the PHP and output as an .html file // Tell php-cgi to run the PHP and output as an .html file
await shell.quiet("\(paths.binPath)/php-cgi -q /tmp/phpmon_phpinfo.php > /tmp/phpmon_phpinfo.html") await container.shell.quiet("\(paths.binPath)/php-cgi -q /tmp/phpmon_phpinfo.php > /tmp/phpmon_phpinfo.html")
return URL(string: "file:///private/tmp/phpmon_phpinfo.html")! return URL(string: "file:///private/tmp/phpmon_phpinfo.html")!
} }
@@ -133,7 +137,7 @@ class Actions {
extensions and/or run `composer global update`. extensions and/or run `composer global update`.
*/ */
public func fixMyValet() async { public func fixMyValet() async {
await InternalSwitcher().performSwitch(to: PhpEnvironments.brewPhpAlias) await InternalSwitcher(container).performSwitch(to: PhpEnvironments.brewPhpAlias)
await brew(container, "services restart \(formulae.dnsmasq)", sudo: formulae.dnsmasq.elevated) await brew(container, "services restart \(formulae.dnsmasq)", sudo: formulae.dnsmasq.elevated)
await brew(container, "services restart \(formulae.php)", sudo: formulae.php.elevated) await brew(container, "services restart \(formulae.php)", sudo: formulae.php.elevated)
await brew(container, "services restart \(formulae.nginx)", sudo: formulae.nginx.elevated) await brew(container, "services restart \(formulae.nginx)", sudo: formulae.nginx.elevated)

View File

@@ -12,11 +12,11 @@ import ContainerMacro
@ContainerAccess @ContainerAccess
struct HomebrewFormulae { struct HomebrewFormulae {
var php: HomebrewFormula { var php: HomebrewFormula {
if phpEnvs.homebrewPackage == nil { if container.phpEnvs.homebrewPackage == nil {
return HomebrewFormula("php", elevated: true) return HomebrewFormula("php", elevated: true)
} }
guard let install = phpEnvs.phpInstall else { guard let install = container.phpEnvs.phpInstall else {
return HomebrewFormula("php", elevated: true) return HomebrewFormula("php", elevated: true)
} }

View File

@@ -36,19 +36,19 @@ class Application {
(This will open the app if it isn't open yet.) (This will open the app if it isn't open yet.)
*/ */
@objc public func openDirectory(file: String) { @objc public func openDirectory(file: String) {
Task { await shell.quiet("/usr/bin/open -a \"\(name)\" \"\(file)\"") } Task { await container.shell.quiet("/usr/bin/open -a \"\(name)\" \"\(file)\"") }
} }
/** Checks if the app is installed. */ /** Checks if the app is installed. */
func isInstalled() async -> Bool { func isInstalled() async -> Bool {
let (process, output) = try! await shell.attach( let (process, output) = try! await container.shell.attach(
"/usr/bin/open -Ra \"\(name)\"", "/usr/bin/open -Ra \"\(name)\"",
didReceiveOutput: { _, _ in }, didReceiveOutput: { _, _ in },
withTimeout: 2.0 withTimeout: 2.0
) )
if shell is TestableShell { if container.shell is TestableShell {
// When testing, check the error output (must not be empty) // When testing, check the error output (must not be empty)
return !output.hasError return !output.hasError
} else { } else {

View File

@@ -74,7 +74,7 @@ class ActivePhpInstallation {
post_max_size: getByteCount(key: "post_max_size") post_max_size: getByteCount(key: "post_max_size")
) )
let paths = shell let paths = container.shell
.sync("\(container.paths.php) --ini | grep -E -o '(/[^ ]+\\.ini)'").out .sync("\(container.paths.php) --ini | grep -E -o '(/[^ ]+\\.ini)'").out
.split(separator: "\n") .split(separator: "\n")
.map { String($0) } .map { String($0) }
@@ -92,7 +92,11 @@ class ActivePhpInstallation {
_or_ if the output contains the word "Warning" or "Error". In normal situations this should not be the case. _or_ if the output contains the word "Warning" or "Error". In normal situations this should not be the case.
*/ */
private func determineVersion() throws { private func determineVersion() throws {
let output = command.execute(path: container.paths.phpConfig, arguments: ["--version"], trimNewlines: true) let output = container.command.execute(
path: container.paths.phpConfig,
arguments: ["--version"],
trimNewlines: true
)
self.hasErrorState = (output == "" || output.contains("Warning") || output.contains("Error")) self.hasErrorState = (output == "" || output.contains("Warning") || output.contains("Error"))
@@ -115,7 +119,11 @@ class ActivePhpInstallation {
- Parameter key: The key of the `ini` value that needs to be retrieved. For example, you can use `memory_limit`. - 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 { private func getByteCount(key: String) -> String {
let value = command.execute(path: container.paths.php, arguments: ["-r", "echo ini_get('\(key)');"], trimNewlines: false) let value = container.command.execute(
path: container.paths.php,
arguments: ["-r", "echo ini_get('\(key)');"],
trimNewlines: false
)
// Check if the value is unlimited // Check if the value is unlimited
if value == "-1" { if value == "-1" {

View File

@@ -13,11 +13,11 @@ import ContainerMacro
@ContainerAccess @ContainerAccess
class Xdebug { class Xdebug {
public var enabled: Bool { public var enabled: Bool {
return phpEnvs.getConfigFile(forKey: "xdebug.mode") != nil return container.phpEnvs.getConfigFile(forKey: "xdebug.mode") != nil
} }
public var activeModes: [String] { public var activeModes: [String] {
guard let file = phpEnvs.getConfigFile(forKey: "xdebug.mode") else { guard let file = container.phpEnvs.getConfigFile(forKey: "xdebug.mode") else {
return [] return []
} }

View File

@@ -134,7 +134,7 @@ class PhpEnvironments {
but currently this is no longer needed. but currently this is no longer needed.
*/ */
public static var switcher: PhpSwitcher { public static var switcher: PhpSwitcher {
return InternalSwitcher() return InternalSwitcher(App.shared.container)
} }
public func reloadPhpVersions() async { public func reloadPhpVersions() async {

View File

@@ -57,8 +57,8 @@ class PhpInstallation {
} }
private func determineVersion(_ phpConfigExecutablePath: String, _ phpExecutablePath: String) { private func determineVersion(_ phpConfigExecutablePath: String, _ phpExecutablePath: String) {
if filesystem.fileExists(phpConfigExecutablePath) { if container.filesystem.fileExists(phpConfigExecutablePath) {
let longVersionString = command.execute( let longVersionString = container.command.execute(
path: phpConfigExecutablePath, path: phpConfigExecutablePath,
arguments: ["--version"], arguments: ["--version"],
trimNewlines: false trimNewlines: false
@@ -79,8 +79,8 @@ class PhpInstallation {
} }
private func determineHealth(_ phpExecutablePath: String) { private func determineHealth(_ phpExecutablePath: String) {
if filesystem.fileExists(phpExecutablePath) { if container.filesystem.fileExists(phpExecutablePath) {
let testCommand = command.execute( let testCommand = container.command.execute(
path: phpExecutablePath, path: phpExecutablePath,
arguments: ["-v"], arguments: ["-v"],
trimNewlines: false, trimNewlines: false,
@@ -97,7 +97,7 @@ class PhpInstallation {
} }
private func determineIniFiles(_ phpExecutablePath: String) { private func determineIniFiles(_ phpExecutablePath: String) {
let paths = shell let paths = container.shell
.sync("\(phpExecutablePath) --ini | grep -E -o '(/[^ ]+\\.ini)'").out .sync("\(phpExecutablePath) --ini | grep -E -o '(/[^ ]+\\.ini)'").out
.split(separator: "\n") .split(separator: "\n")
.map { String($0) } .map { String($0) }

View File

@@ -26,7 +26,7 @@ class InternalSwitcher: PhpSwitcher {
let versions = getVersionsToBeHandled(version) let versions = getVersionsToBeHandled(version)
await withTaskGroup(of: String.self, body: { group in await withTaskGroup(of: String.self, body: { group in
for available in phpEnvs.availablePhpVersions { for available in container.phpEnvs.availablePhpVersions {
group.addTask { group.addTask {
await self.unlinkAndStopPhpVersion(available) await self.unlinkAndStopPhpVersion(available)
return available return available
@@ -103,7 +103,7 @@ class InternalSwitcher: PhpSwitcher {
if Valet.enabled(feature: .isolatedSites) && primary { if Valet.enabled(feature: .isolatedSites) && primary {
let socketVersion = version.replacingOccurrences(of: ".", with: "") let socketVersion = version.replacingOccurrences(of: ".", with: "")
await shell.quiet("ln -sF ~/.config/valet/valet\(socketVersion).sock ~/.config/valet/valet.sock") await container.shell.quiet("ln -sF ~/.config/valet/valet\(socketVersion).sock ~/.config/valet/valet.sock")
Log.info("Symlinked new socket version (valet\(socketVersion).sock → valet.sock).") Log.info("Symlinked new socket version (valet\(socketVersion).sock → valet.sock).")
} }
} }

View File

@@ -7,14 +7,17 @@
// //
class Container { class Container {
// Core abstractions
var shell: ShellProtocol! var shell: ShellProtocol!
var filesystem: FileSystemProtocol! var filesystem: FileSystemProtocol!
var command: CommandProtocol! var command: CommandProtocol!
// Additional abstractions
var paths: Paths! var paths: Paths!
var phpEnvs: PhpEnvironments! var phpEnvs: PhpEnvironments!
var favorites: Favorites! var favorites: Favorites!
// TODO: Pending a rename
var warningManager: WarningManager! var warningManager: WarningManager!
init() {} init() {}

View File

@@ -36,7 +36,7 @@ class ServicesManager: ObservableObject {
} }
var formulae: [HomebrewFormula] { var formulae: [HomebrewFormula] {
let f = HomebrewFormulae() let f = HomebrewFormulae(container)
var formulae = [ var formulae = [
f.php, f.php,

View File

@@ -30,7 +30,7 @@ import ContainerMacro
return return
} }
phpEnvs.isBusy = true container.phpEnvs.isBusy = true
window = TerminalProgressWindowController.display( window = TerminalProgressWindowController.display(
title: "alert.composer_progress.title".localized, title: "alert.composer_progress.title".localized,
@@ -57,7 +57,7 @@ import ContainerMacro
self.window?.addToConsole("\(command)\n") self.window?.addToConsole("\(command)\n")
let (process, _) = try await shell.attach( let (process, _) = try await container.shell.attach(
command, command,
didReceiveOutput: { [weak self] (incoming, _) in didReceiveOutput: { [weak self] (incoming, _) in
guard let window = self?.window else { return } guard let window = self?.window else { return }
@@ -113,7 +113,7 @@ import ContainerMacro
// MARK: Main Menu Update // MARK: Main Menu Update
private func removeBusyStatus() { private func removeBusyStatus() {
phpEnvs.isBusy = false container.phpEnvs.isBusy = false
} }
// MARK: Alert // MARK: Alert

View File

@@ -55,7 +55,7 @@ class BrewPermissionFixer {
whether the Homebrew binary directory for the given PHP version is owned by root. whether the Homebrew binary directory for the given PHP version is owned by root.
*/ */
private func determineBrokenFormulae() async { private func determineBrokenFormulae() async {
let formulae = phpEnvs.cachedPhpInstallations.keys let formulae = container.phpEnvs.cachedPhpInstallations.keys
for formula in formulae { for formula in formulae {
let realFormula = formula == PhpEnvironments.brewPhpAlias let realFormula = formula == PhpEnvironments.brewPhpAlias

View File

@@ -11,7 +11,7 @@ import ContainerMacro
@ContainerAccess @ContainerAccess
class Brew { class Brew {
static let shared = Brew() static let shared = Brew(App.shared.container)
/// Formulae that can be observed. /// Formulae that can be observed.
var formulae = BrewFormulaeObservable() var formulae = BrewFormulaeObservable()
@@ -21,7 +21,7 @@ class Brew {
/// Determine which version of Homebrew is installed. /// Determine which version of Homebrew is installed.
public func determineVersion() async { public func determineVersion() async {
let output = await shell.pipe("\(container.paths.brew) --version") let output = await container.shell.pipe("\(container.paths.brew) --version")
self.version = try? VersionNumber.parse(output.out) self.version = try? VersionNumber.parse(output.out)
if let version = version { if let version = version {

View File

@@ -12,7 +12,11 @@ import ContainerMacro
@ContainerAccess @ContainerAccess
class BrewDiagnostics { class BrewDiagnostics {
public static let shared = BrewDiagnostics() public static let shared = BrewDiagnostics(App.shared.container)
var filesystem: FileSystemProtocol {
return container.filesystem
}
/** /**
Determines the Homebrew taps the user has installed. Determines the Homebrew taps the user has installed.
@@ -23,7 +27,7 @@ class BrewDiagnostics {
Load which taps are installed. Load which taps are installed.
*/ */
public func loadInstalledTaps() async { public func loadInstalledTaps() async {
installedTaps = await shell installedTaps = await container.shell
.pipe("\(container.paths.brew) tap") .pipe("\(container.paths.brew) tap")
.out .out
.split(separator: "\n") .split(separator: "\n")
@@ -123,7 +127,7 @@ class BrewDiagnostics {
public func checkForValetMisconfiguration() async { public func checkForValetMisconfiguration() async {
Log.info("Checking for PHP-FPM issues with Valet...") Log.info("Checking for PHP-FPM issues with Valet...")
guard let install = phpEnvs.phpInstall else { guard let install = container.phpEnvs.phpInstall else {
Log.info("Will skip check for issues if no PHP version is linked.") Log.info("Will skip check for issues if no PHP version is linked.")
return return
} }
@@ -132,7 +136,7 @@ class BrewDiagnostics {
let primary = install.version.short let primary = install.version.short
// Versions to be handled // Versions to be handled
let switcher = InternalSwitcher() let switcher = InternalSwitcher(container)
for version in switcher.getVersionsToBeHandled(primary) for version in switcher.getVersionsToBeHandled(primary)
where await switcher.ensureValetConfigurationIsValidForPhpVersion(version) { where await switcher.ensureValetConfigurationIsValidForPhpVersion(version) {
@@ -162,7 +166,7 @@ class BrewDiagnostics {
Check if the alias conflict as documented in `checkForCaskConflict` actually occurred. Check if the alias conflict as documented in `checkForCaskConflict` actually occurred.
*/ */
private func hasAliasConflict() async -> Bool { private func hasAliasConflict() async -> Bool {
let tapAlias = await shell.pipe("brew info shivammathur/php/php --json").out let tapAlias = await container.shell.pipe("brew info shivammathur/php/php --json").out
if tapAlias.contains("brew tap shivammathur/php") || tapAlias.contains("Error") || tapAlias.isEmpty { if tapAlias.contains("brew tap shivammathur/php") || tapAlias.contains("Error") || tapAlias.isEmpty {
Log.info("The user does not appear to have tapped: shivammathur/php") Log.info("The user does not appear to have tapped: shivammathur/php")
@@ -181,8 +185,10 @@ class BrewDiagnostics {
+ "This could be a problem!") + "This could be a problem!")
Log.info("Determining whether both of these versions are installed...") Log.info("Determining whether both of these versions are installed...")
let bothInstalled = phpEnvs.availablePhpVersions.contains(tapPhp.version) let availablePhpVersions = container.phpEnvs.availablePhpVersions
&& phpEnvs.availablePhpVersions.contains(PhpEnvironments.brewPhpAlias)
let bothInstalled = availablePhpVersions.contains(tapPhp.version)
&& availablePhpVersions.contains(PhpEnvironments.brewPhpAlias)
if bothInstalled { if bothInstalled {
Log.warn("Both conflicting aliases seem to be installed, warning the user!") Log.warn("Both conflicting aliases seem to be installed, warning the user!")
@@ -219,7 +225,7 @@ class BrewDiagnostics {
If the JSON response cannot be parsed, Homebrew is probably out of date. If the JSON response cannot be parsed, Homebrew is probably out of date.
*/ */
public func cannotLoadService(_ name: String) async -> Bool { public func cannotLoadService(_ name: String) async -> Bool {
let nginxJson = await shell let nginxJson = await container.shell
.pipe("sudo \(container.paths.brew) services info \(name) --json") .pipe("sudo \(container.paths.brew) services info \(name) --json")
.out .out

View File

@@ -35,7 +35,7 @@ class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae {
\(container.paths.brew) outdated --json --formulae \(container.paths.brew) outdated --json --formulae
""" """
let rawJsonText = await shell.pipe(command).out let rawJsonText = await container.shell.pipe(command).out
.data(using: .utf8)! .data(using: .utf8)!
outdated = try? JSONDecoder().decode( outdated = try? JSONDecoder().decode(
OutdatedFormulae.self, OutdatedFormulae.self,
@@ -50,7 +50,7 @@ class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae {
var upgradeVersion: String? var upgradeVersion: String?
var isPrerelease: Bool = Constants.ExperimentalPhpVersions.contains(version) var isPrerelease: Bool = Constants.ExperimentalPhpVersions.contains(version)
if let install = phpEnvs.cachedPhpInstallations[version] { if let install = container.phpEnvs.cachedPhpInstallations[version] {
fullVersion = install.versionNumber.text fullVersion = install.versionNumber.text
fullVersion = install.isPreRelease ? "\(fullVersion!)-dev" : fullVersion fullVersion = install.isPreRelease ? "\(fullVersion!)-dev" : fullVersion

View File

@@ -68,7 +68,7 @@ class InstallPhpExtensionCommand: BrewCommand {
// Restart PHP-FPM // Restart PHP-FPM
if let installed = self.installing.first { if let installed = self.installing.first {
await Actions().restartPhpFpm(version: installed.phpVersion) await Actions(container).restartPhpFpm(version: installed.phpVersion)
} }
// Check which version of PHP are now installed // Check which version of PHP are now installed

View File

@@ -31,7 +31,7 @@ class RemovePhpExtensionCommand: BrewCommand {
)) ))
// Keep track of the file that contains the information about the extension // Keep track of the file that contains the information about the extension
let existing = phpEnvs let existing = container.phpEnvs
.cachedPhpInstallations[phpExtension.phpVersion]? .cachedPhpInstallations[phpExtension.phpVersion]?
.extensions.first(where: { ext in .extensions.first(where: { ext in
ext.name == phpExtension.name ext.name == phpExtension.name
@@ -64,9 +64,9 @@ class RemovePhpExtensionCommand: BrewCommand {
await performExtensionCleanup(for: ext) await performExtensionCleanup(for: ext)
} }
_ = await phpEnvs.detectPhpVersions() _ = await container.phpEnvs.detectPhpVersions()
await Actions().restartPhpFpm(version: phpExtension.phpVersion) await Actions(container).restartPhpFpm(version: phpExtension.phpVersion)
await MainMenu.shared.refreshActiveInstallation() await MainMenu.shared.refreshActiveInstallation()
@@ -81,7 +81,7 @@ class RemovePhpExtensionCommand: BrewCommand {
// The extension's default configuration file can be removed // The extension's default configuration file can be removed
Log.info("The extension was found in a default extension .ini location. Purging that .ini file.") Log.info("The extension was found in a default extension .ini location. Purging that .ini file.")
do { do {
try filesystem.remove(ext.file) try container.filesystem.remove(ext.file)
} catch { } catch {
Log.err("The file `\(ext.file)` could not be removed.") Log.err("The file `\(ext.file)` could not be removed.")
} }

View File

@@ -71,11 +71,11 @@ class ModifyPhpVersionCommand: BrewCommand {
} else { } else {
// Simply upgrade `php` to the latest version // Simply upgrade `php` to the latest version
try await self.upgradeMainPhpFormula(unavailable!, onProgress) try await self.upgradeMainPhpFormula(unavailable!, onProgress)
await phpEnvs.determinePhpAlias() await container.phpEnvs.determinePhpAlias()
} }
// Re-check the installed versions // Re-check the installed versions
_ = await phpEnvs.detectPhpVersions() _ = await container.phpEnvs.detectPhpVersions()
// After performing operations, attempt to run repairs if needed // After performing operations, attempt to run repairs if needed
try await self.repairBrokenPackages(onProgress) try await self.repairBrokenPackages(onProgress)
@@ -103,7 +103,7 @@ class ModifyPhpVersionCommand: BrewCommand {
""" """
// Run the upgrade command // Run the upgrade command
try await run(shell: shell, command, onProgress) try await run(shell: container.shell, command, onProgress)
} }
private func upgradePackages(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws { private func upgradePackages(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
@@ -119,7 +119,7 @@ class ModifyPhpVersionCommand: BrewCommand {
\(container.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) try await run(shell: container.shell, command, onProgress)
} }
private func installPackages(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws { private func installPackages(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
@@ -134,13 +134,13 @@ class ModifyPhpVersionCommand: BrewCommand {
\(container.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) try await run(shell: container.shell, command, onProgress)
} }
private func repairBrokenPackages(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws { private func repairBrokenPackages(_ onProgress: @escaping (BrewCommandProgress) -> Void) async throws {
// Determine which PHP installations are considered unhealthy // Determine which PHP installations are considered unhealthy
// Build a list of formulae to reinstall // Build a list of formulae to reinstall
let requiringRepair = phpEnvs let requiringRepair = container.phpEnvs
.cachedPhpInstallations.values .cachedPhpInstallations.values
.filter({ !$0.isHealthy }) .filter({ !$0.isHealthy })
.map { installation in .map { installation in
@@ -166,7 +166,7 @@ class ModifyPhpVersionCommand: BrewCommand {
\(container.paths.brew) reinstall \(requiringRepair.joined(separator: " ")) --force \(container.paths.brew) reinstall \(requiringRepair.joined(separator: " ")) --force
""" """
try await run(shell: shell, command, onProgress) try await run(shell: container.shell, command, onProgress)
} }
private func completedOperations(_ onProgress: @escaping (BrewCommandProgress) -> Void) async { private func completedOperations(_ onProgress: @escaping (BrewCommandProgress) -> Void) async {
@@ -177,7 +177,7 @@ class ModifyPhpVersionCommand: BrewCommand {
await BrewDiagnostics.shared.checkForOutdatedPhpInstallationSymlinks() await BrewDiagnostics.shared.checkForOutdatedPhpInstallationSymlinks()
// Check which version of PHP are now installed // Check which version of PHP are now installed
_ = await phpEnvs.detectPhpVersions() _ = await container.phpEnvs.detectPhpVersions()
// Keep track of the currently installed version // Keep track of the currently installed version
await MainMenu.shared.refreshActiveInstallation() await MainMenu.shared.refreshActiveInstallation()

View File

@@ -46,7 +46,7 @@ class RemovePhpVersionCommand: BrewCommand {
""" """
do { do {
try await BrewPermissionFixer().fixPermissions() try await BrewPermissionFixer(container).fixPermissions()
} catch { } catch {
return return
} }
@@ -67,7 +67,7 @@ class RemovePhpVersionCommand: BrewCommand {
if process.terminationStatus <= 0 { if process.terminationStatus <= 0 {
onProgress(.create(value: 0.95, title: getCommandTitle(), description: "phpman.steps.reloading".localized)) onProgress(.create(value: 0.95, title: getCommandTitle(), description: "phpman.steps.reloading".localized))
_ = await phpEnvs.detectPhpVersions() _ = await container.phpEnvs.detectPhpVersions()
await MainMenu.shared.refreshActiveInstallation() await MainMenu.shared.refreshActiveInstallation()

View File

@@ -62,7 +62,7 @@ class ValetUpgrader {
} }
@MainActor private static func upgradeValet() { @MainActor private static func upgradeValet() {
ComposerWindow().updateGlobalDependencies( ComposerWindow(App.shared.container).updateGlobalDependencies(
notify: true, notify: true,
completion: { success in completion: { success in
if success { if success {

View File

@@ -16,20 +16,20 @@ struct ValetInteractionError: Error {
@ContainerAccess @ContainerAccess
class ValetInteractor { class ValetInteractor {
static var shared = ValetInteractor() static var shared = ValetInteractor(App.shared.container)
public static func useFake() { public static func useFake() {
ValetInteractor.shared = FakeValetInteractor() ValetInteractor.shared = FakeValetInteractor(App.shared.container)
} }
// MARK: - Managing Domains // MARK: - Managing Domains
public func link(path: String, domain: String) async throws { public func link(path: String, domain: String) async throws {
await shell.quiet("cd '\(path)' && \(container.paths.valet) link '\(domain)' && valet links") await container.shell.quiet("cd '\(path)' && \(container.paths.valet) link '\(domain)' && valet links")
} }
public func unlink(site: ValetSite) async throws { public func unlink(site: ValetSite) async throws {
await shell.quiet("valet unlink '\(site.name)'") await container.shell.quiet("valet unlink '\(site.name)'")
} }
public func proxy(domain: String, proxy: String, secure: Bool) async throws { public func proxy(domain: String, proxy: String, secure: Bool) async throws {
@@ -37,12 +37,12 @@ class ValetInteractor {
? "\(container.paths.valet) proxy \(domain) \(proxy) --secure" ? "\(container.paths.valet) proxy \(domain) \(proxy) --secure"
: "\(container.paths.valet) proxy \(domain) \(proxy)" : "\(container.paths.valet) proxy \(domain) \(proxy)"
await shell.quiet(command) await container.shell.quiet(command)
await Actions().restartNginx() await Actions(container).restartNginx()
} }
public func remove(proxy: ValetProxy) async throws { public func remove(proxy: ValetProxy) async throws {
await shell.quiet("valet unproxy '\(proxy.domain)'") await container.shell.quiet("valet unproxy '\(proxy.domain)'")
} }
// MARK: - Modifying Domains // MARK: - Modifying Domains
@@ -64,7 +64,7 @@ class ValetInteractor {
} }
// Run the command // Run the command
await shell.quiet(command) await container.shell.quiet(command)
// Check if the secured status has actually changed // Check if the secured status has actually changed
site.determineSecured() site.determineSecured()
@@ -89,7 +89,7 @@ class ValetInteractor {
// Run the commands // Run the commands
for command in commands { for command in commands {
await shell.quiet(command) await container.shell.quiet(command)
} }
// Check if the secured status has actually changed // Check if the secured status has actually changed
@@ -101,14 +101,14 @@ class ValetInteractor {
} }
// Restart nginx to load the new configuration // Restart nginx to load the new configuration
await Actions().restartNginx() await Actions(container).restartNginx()
} }
public func isolate(site: ValetSite, version: String) async throws { public func isolate(site: ValetSite, version: String) async throws {
let command = "sudo \(container.paths.valet) isolate php@\(version) --site '\(site.name)'" let command = "sudo \(container.paths.valet) isolate php@\(version) --site '\(site.name)'"
// Run the command // Run the command
await shell.quiet(command) await container.shell.quiet(command)
// Check if the secured status has actually changed // Check if the secured status has actually changed
site.determineIsolated() site.determineIsolated()
@@ -124,7 +124,7 @@ class ValetInteractor {
let command = "sudo \(container.paths.valet) unisolate --site '\(site.name)'" let command = "sudo \(container.paths.valet) unisolate --site '\(site.name)'"
// Run the command // Run the command
await shell.quiet(command) await container.shell.quiet(command)
// Check if the secured status has actually changed // Check if the secured status has actually changed
site.determineIsolated() site.determineIsolated()

View File

@@ -17,7 +17,7 @@ class ValetDomainScanner: DomainScanner {
func resolveSiteCount(paths: [String]) -> Int { func resolveSiteCount(paths: [String]) -> Int {
return paths.map { path in return paths.map { path in
do { do {
let entries = try filesystem let entries = try container.filesystem
.getShallowContentsOfDirectory(path) .getShallowContentsOfDirectory(path)
return entries return entries
@@ -37,7 +37,7 @@ class ValetDomainScanner: DomainScanner {
paths.forEach { path in paths.forEach { path in
do { do {
let entries = try filesystem let entries = try container.filesystem
.getShallowContentsOfDirectory(path) .getShallowContentsOfDirectory(path)
return entries.forEach { return entries.forEach {
@@ -61,7 +61,7 @@ class ValetDomainScanner: DomainScanner {
// Get the TLD from the global Valet object // Get the TLD from the global Valet object
let tld = Valet.shared.config.tld let tld = Valet.shared.config.tld
if !filesystem.anyExists(path) { if !container.filesystem.anyExists(path) {
Log.warn("Could not parse the site: \(path), skipping!") Log.warn("Could not parse the site: \(path), skipping!")
} }
@@ -71,9 +71,9 @@ class ValetDomainScanner: DomainScanner {
return nil return nil
} }
if filesystem.isSymlink(path) { if container.filesystem.isSymlink(path) {
return ValetSite(container, aliasPath: path, tld: tld) return ValetSite(container, aliasPath: path, tld: tld)
} else if filesystem.isDirectory(path) { } else if container.filesystem.isDirectory(path) {
return ValetSite(container, absolutePath: path, tld: tld) return ValetSite(container, absolutePath: path, tld: tld)
} }

View File

@@ -10,7 +10,7 @@ import Foundation
class ValetScanner { class ValetScanner {
static var active: DomainScanner = ValetDomainScanner() static var active: DomainScanner = ValetDomainScanner(App.shared.container)
public static func useFake() { public static func useFake() {
ValetScanner.active = FakeDomainScanner() ValetScanner.active = FakeDomainScanner()

View File

@@ -58,7 +58,7 @@ class ValetSite: ValetListable {
/// Which version of PHP is actually used to serve this site. /// Which version of PHP is actually used to serve this site.
var servingPhpVersion: String { var servingPhpVersion: String {
return self.isolatedPhpVersion?.versionNumber.short return self.isolatedPhpVersion?.versionNumber.short
?? phpEnvs.phpInstall?.version.short ?? container.phpEnvs.phpInstall?.version.short
?? "???" ?? "???"
} }
@@ -107,12 +107,12 @@ class ValetSite: ValetListable {
*/ */
public func determineIsolated() { public func determineIsolated() {
if let version = ValetSite.isolatedVersion(container, "~/.config/valet/Nginx/\(self.name).\(self.tld)") { if let version = ValetSite.isolatedVersion(container, "~/.config/valet/Nginx/\(self.name).\(self.tld)") {
if !phpEnvs.cachedPhpInstallations.keys.contains(version) { if !container.phpEnvs.cachedPhpInstallations.keys.contains(version) {
Log.err("The PHP version \(version) is isolated for the site \(self.name) " Log.err("The PHP version \(version) is isolated for the site \(self.name) "
+ "but that PHP version is unavailable.") + "but that PHP version is unavailable.")
return return
} }
self.isolatedPhpVersion = phpEnvs.cachedPhpInstallations[version] self.isolatedPhpVersion = container.phpEnvs.cachedPhpInstallations[version]
} else { } else {
self.isolatedPhpVersion = nil self.isolatedPhpVersion = nil
} }
@@ -123,7 +123,10 @@ class ValetSite: ValetListable {
- Note: The file is not validated, only its presence is checked. - Note: The file is not validated, only its presence is checked.
*/ */
public func determineSecured() { public func determineSecured() {
secured = filesystem.fileExists("~/.config/valet/Certificates/\(self.name).\(self.tld).key") secured = container.filesystem
.fileExists("~/.config/valet/Certificates/\(self.name).\(self.tld).key")
// TODO: Also verify the certificate hasn't expired
} }
/** /**
@@ -185,7 +188,7 @@ class ValetSite: ValetListable {
let path = "\(absolutePath)/composer.json" let path = "\(absolutePath)/composer.json"
do { do {
if filesystem.fileExists(path) { if container.filesystem.fileExists(path) {
let decoded = try JSONDecoder().decode( let decoded = try JSONDecoder().decode(
ComposerJson.self, ComposerJson.self,
from: String( from: String(
@@ -216,7 +219,7 @@ class ValetSite: ValetListable {
for (suffix, source) in files { for (suffix, source) in files {
do { do {
let path = "\(absolutePath)/\(suffix)" let path = "\(absolutePath)/\(suffix)"
if filesystem.fileExists(path) { if container.filesystem.fileExists(path) {
return try self.handleValetFile(path, source) return try self.handleValetFile(path, source)
} }
} catch { } catch {
@@ -253,7 +256,7 @@ class ValetSite: ValetListable {
return return
} }
guard let linked = phpEnvs.phpInstall else { guard let linked = container.phpEnvs.phpInstall else {
self.isCompatibleWithPreferredPhpVersion = false self.isCompatibleWithPreferredPhpVersion = false
return return
} }

View File

@@ -68,8 +68,8 @@ class Valet {
} }
lazy var installed: Bool = { lazy var installed: Bool = {
return filesystem.fileExists(container.paths.binPath.appending("/valet")) return container.filesystem.fileExists(container.paths.binPath.appending("/valet"))
&& filesystem.anyExists("~/.config/valet") && container.filesystem.anyExists("~/.config/valet")
}() }()
/** /**
@@ -92,7 +92,7 @@ class Valet {
and the app cannot start. and the app cannot start.
*/ */
public func updateVersionNumber() async { public func updateVersionNumber() async {
let output = await shell.pipe("valet --version").out let output = await container.shell.pipe("valet --version").out
// Failure condition #1: does not contain Laravel Valet // Failure condition #1: does not contain Laravel Valet
if !output.contains("Laravel Valet") { if !output.contains("Laravel Valet") {
@@ -122,7 +122,9 @@ class Valet {
do { do {
config = try JSONDecoder().decode( config = try JSONDecoder().decode(
Valet.Configuration.self, Valet.Configuration.self,
from: filesystem.getStringFromFile("~/.config/valet/config.json").data(using: .utf8)! from: container.filesystem
.getStringFromFile("~/.config/valet/config.json")
.data(using: .utf8)!
) )
} catch { } catch {
Log.err(error) Log.err(error)
@@ -186,7 +188,7 @@ class Valet {
return return
} }
if phpEnvs.phpInstall == nil { if container.phpEnvs.phpInstall == nil {
Log.info("Cannot validate Valet version if no PHP version is linked.") Log.info("Cannot validate Valet version if no PHP version is linked.")
return return
} }
@@ -209,7 +211,7 @@ class Valet {
Determine if any platform issues are detected when running `valet --version`. Determine if any platform issues are detected when running `valet --version`.
*/ */
public func hasPlatformIssues() async -> Bool { public func hasPlatformIssues() async -> Bool {
return await shell.pipe("valet --version") return await container.shell.pipe("valet --version")
.out.contains("Composer detected issues in your platform") .out.contains("Composer detected issues in your platform")
} }
@@ -243,7 +245,7 @@ class Valet {
that means that Valet won't work properly. that means that Valet won't work properly.
*/ */
func phpFpmConfigurationValid() async -> Bool { func phpFpmConfigurationValid() async -> Bool {
guard let version = phpEnvs.currentInstall?.version else { guard let version = container.phpEnvs.currentInstall?.version else {
Log.info("Cannot check PHP-FPM status: no version of PHP is active") Log.info("Cannot check PHP-FPM status: no version of PHP is active")
return true return true
} }
@@ -251,12 +253,13 @@ class Valet {
if version.short == "5.6" { if version.short == "5.6" {
// The main PHP config file should contain `valet.sock` and then we're probably fine? // The main PHP config file should contain `valet.sock` and then we're probably fine?
let fileName = "\(container.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 return await container.shell.pipe("cat \(fileName)").out
.contains("valet.sock") .contains("valet.sock")
} }
// Make sure to check if valet-fpm.conf exists. If it does, we should be fine :) // Make sure to check if valet-fpm.conf exists. If it does, we should be fine :)
return filesystem.fileExists("\(container.paths.etcPath)/php/\(version.short)/php-fpm.d/valet-fpm.conf") return container.filesystem
.fileExists("\(container.paths.etcPath)/php/\(version.short)/php-fpm.d/valet-fpm.conf")
} }
/** /**

View File

@@ -14,7 +14,7 @@ extension MainMenu {
@MainActor @objc func linkPhpBinary() { @MainActor @objc func linkPhpBinary() {
Task { Task {
await Actions().linkPhp() await actions.linkPhp()
} }
} }
@@ -45,7 +45,7 @@ extension MainMenu {
} }
asyncExecution { asyncExecution {
try Actions().fixHomebrewPermissions() try self.actions.fixHomebrewPermissions()
} success: { } success: {
NVAlert() NVAlert()
.withInformation( .withInformation(
@@ -62,27 +62,27 @@ extension MainMenu {
@objc func restartPhpFpm() { @objc func restartPhpFpm() {
Task { // Simple restart service Task { // Simple restart service
await Actions().restartPhpFpm() await actions.restartPhpFpm()
} }
} }
@objc func restartNginx() { @objc func restartNginx() {
Task { // Simple restart service Task { // Simple restart service
await Actions().restartNginx() await actions.restartNginx()
} }
} }
@objc func restartDnsMasq() { @objc func restartDnsMasq() {
Task { // Simple restart service Task { // Simple restart service
await Actions().restartDnsMasq() await actions.restartDnsMasq()
} }
} }
@MainActor @objc func restartValetServices() { @MainActor @objc func restartValetServices() {
Task { // Restart services and show notification Task { // Restart services and show notification
await Actions().restartDnsMasq() await actions.restartDnsMasq()
await Actions().restartPhpFpm() await actions.restartPhpFpm()
await Actions().restartNginx() await actions.restartNginx()
LocalNotification.send( LocalNotification.send(
title: "notification.services_restarted".localized, title: "notification.services_restarted".localized,
@@ -94,7 +94,7 @@ extension MainMenu {
@MainActor @objc func stopValetServices() { @MainActor @objc func stopValetServices() {
Task { // Stop services and show notification Task { // Stop services and show notification
await Actions().stopValetServices() await actions.stopValetServices()
LocalNotification.send( LocalNotification.send(
title: "notification.services_stopped".localized, title: "notification.services_stopped".localized,
@@ -129,7 +129,7 @@ extension MainMenu {
} }
do { do {
var modes = Xdebug().activeModes var modes = Xdebug(container).activeModes
if let index = modes.firstIndex(of: sender.mode) { if let index = modes.firstIndex(of: sender.mode) {
modes.remove(at: index) modes.remove(at: index)
@@ -157,7 +157,7 @@ extension MainMenu {
await sender.phpExtension?.toggle() await sender.phpExtension?.toggle()
if Preferences.isEnabled(.autoServiceRestartAfterExtensionToggle) { if Preferences.isEnabled(.autoServiceRestartAfterExtensionToggle) {
await Actions().restartPhpFpm() await actions.restartPhpFpm()
} }
} }
} }
@@ -212,14 +212,14 @@ extension MainMenu {
@objc func openPhpInfo() { @objc func openPhpInfo() {
asyncWithBusyUI { asyncWithBusyUI {
Task { // Create temporary file and open the URL Task { // Create temporary file and open the URL
let url = await Actions().createTempPhpInfoFile() let url = await self.actions.createTempPhpInfoFile()
NSWorkspace.shared.open(url) NSWorkspace.shared.open(url)
} }
} }
} }
@MainActor @objc func updateGlobalComposerDependencies() { @MainActor @objc func updateGlobalComposerDependencies() {
ComposerWindow().updateGlobalDependencies( ComposerWindow(container).updateGlobalDependencies(
notify: true, notify: true,
completion: { _ in } completion: { _ in }
) )
@@ -232,23 +232,23 @@ extension MainMenu {
} }
if install.hasErrorState { if install.hasErrorState {
Actions().openGenericPhpConfigFolder() actions.openGenericPhpConfigFolder()
return return
} }
Actions().openPhpConfigFolder(version: install.version.short) actions.openPhpConfigFolder(version: install.version.short)
} }
@objc func openPhpMonitorConfigurationFile() { @objc func openPhpMonitorConfigurationFile() {
Actions().openPhpMonitorConfigFile() actions.openPhpMonitorConfigFile()
} }
@objc func openGlobalComposerFolder() { @objc func openGlobalComposerFolder() {
Actions().openGlobalComposerFolder() actions.openGlobalComposerFolder()
} }
@objc func openValetConfigFolder() { @objc func openValetConfigFolder() {
Actions().openValetConfigFolder() actions.openValetConfigFolder()
} }
@objc func switchToPhpVersion(sender: PhpMenuItem) { @objc func switchToPhpVersion(sender: PhpMenuItem) {

View File

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

View File

@@ -38,7 +38,7 @@ extension MainMenu {
// Run composer updates // Run composer updates
if Preferences.isEnabled(.autoComposerGlobalUpdateAfterSwitch) { if Preferences.isEnabled(.autoComposerGlobalUpdateAfterSwitch) {
ComposerWindow().updateGlobalDependencies( ComposerWindow(App.shared.container).updateGlobalDependencies(
notify: false, notify: false,
completion: { _ in completion: { _ in
self.notifyAboutVersionChange(to: version) self.notifyAboutVersionChange(to: version)
@@ -99,7 +99,7 @@ extension MainMenu {
.withPrimary(text: "alert.global_composer_platform_issues.buttons.update".localized, action: { alert in .withPrimary(text: "alert.global_composer_platform_issues.buttons.update".localized, action: { alert in
alert.close(with: .OK) alert.close(with: .OK)
Log.info("The user has chosen to update global dependencies.") Log.info("The user has chosen to update global dependencies.")
ComposerWindow().updateGlobalDependencies( ComposerWindow(App.shared.container).updateGlobalDependencies(
notify: true, notify: true,
completion: { success in completion: { success in
Log.info("Dependencies updated successfully: \(success)") Log.info("Dependencies updated successfully: \(success)")

View File

@@ -14,6 +14,10 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
return App.shared.container return App.shared.container
} }
var actions: Actions {
return Actions(container)
}
static let shared = MainMenu() static let shared = MainMenu()
override init() { override init() {

View File

@@ -275,7 +275,7 @@ extension StatusMenu {
// MARK: - Xdebug // MARK: - Xdebug
@MainActor func addXdebugMenuItem() { @MainActor func addXdebugMenuItem() {
let xdebug = Xdebug() let xdebug = Xdebug(container)
if !xdebug.enabled { if !xdebug.enabled {
addItem(NSMenuItem.separator()) addItem(NSMenuItem.separator())

View File

@@ -83,7 +83,7 @@ struct Preset: Codable, Equatable {
if self.version != nil { if self.version != nil {
if await !switchToPhpVersionIfValid() { if await !switchToPhpVersionIfValid() {
PresetHelper.rollbackPreset = nil PresetHelper.rollbackPreset = nil
await Actions().restartPhpFpm() await Actions(container).restartPhpFpm()
return return
} }
} }
@@ -111,7 +111,7 @@ struct Preset: Codable, Equatable {
PresetHelper.loadRollbackPresetFromFile() PresetHelper.loadRollbackPresetFromFile()
// Restart PHP FPM process (also reloads menu, which will show the preset rollback) // Restart PHP FPM process (also reloads menu, which will show the preset rollback)
await Actions().restartPhpFpm() await Actions(container).restartPhpFpm()
Task { @MainActor in Task { @MainActor in
// Show the correct notification // Show the correct notification

View File

@@ -16,7 +16,7 @@ class InstallHomebrew {
"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
""" """
_ = try await shell.attach(script, didReceiveOutput: { (string: String, _: ShellStream) in _ = try await container.shell.attach(script, didReceiveOutput: { (string: String, _: ShellStream) in
print(string) print(string)
}, withTimeout: 60 * 10) }, withTimeout: 60 * 10)
} }

View File

@@ -14,7 +14,7 @@ class ZshRunCommand {
Adds a given line to .zshrc, which may be needed to adjust the PATH. Adds a given line to .zshrc, which may be needed to adjust the PATH.
*/ */
private func add(_ text: String) async -> Bool { private func add(_ text: String) async -> Bool {
let outcome = await shell.pipe(""" let outcome = await container.shell.pipe("""
touch ~/.zshrc && \ touch ~/.zshrc && \
grep -qxF '\(text)' ~/.zshrc \ grep -qxF '\(text)' ~/.zshrc \
|| echo '\n\n\(text)\n' >> ~/.zshrc || echo '\n\n\(text)\n' >> ~/.zshrc

View File

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

View File

@@ -16,7 +16,7 @@ struct FileExistenceCheck {
@ContainerAccess @ContainerAccess
class PhpConfigChecker { class PhpConfigChecker {
public static var shared = PhpConfigChecker() public static var shared = PhpConfigChecker(App.shared.container)
var missing: [String] = [] var missing: [String] = []

View File

@@ -36,7 +36,7 @@ extension WarningManager {
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries", url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries",
fix: self.container.paths.shell == "/bin/zsh" ? { fix: self.container.paths.shell == "/bin/zsh" ? {
// Add to PATH // Add to PATH
await ZshRunCommand().addPhpMonitorPath() await ZshRunCommand(self.container).addPhpMonitorPath()
// Finally, perform environment checks again // Finally, perform environment checks again
await self.checkEnvironment() await self.checkEnvironment()
} : nil } : nil
@@ -44,7 +44,7 @@ extension WarningManager {
Warning( Warning(
command: { command: {
self.container.phpEnvs.currentInstall?.extensions.contains { $0.name == "xdebug" } ?? false self.container.phpEnvs.currentInstall?.extensions.contains { $0.name == "xdebug" } ?? false
&& !Xdebug().enabled && !Xdebug(self.container).enabled
}, },
name: "Missing configuration file for `xdebug.mode`", name: "Missing configuration file for `xdebug.mode`",
title: "warnings.xdebug_conf_missing.title", title: "warnings.xdebug_conf_missing.title",

View File

@@ -25,7 +25,7 @@ class PhpVersionManagerWindowController: PMWindowController {
windowController.window = NSWindow() windowController.window = NSWindow()
windowController.view = PhpVersionManagerView( windowController.view = PhpVersionManagerView(
formulae: Brew.shared.formulae, formulae: Brew.shared.formulae,
handler: BrewPhpFormulaeHandler() handler: BrewPhpFormulaeHandler(App.shared.container)
) )
guard let window = windowController.window else { return } guard let window = windowController.window else { return }