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

View File

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

View File

@@ -10,9 +10,8 @@ import ContainerMacro
@ContainerAccess
class MyClass {
func doSomething() {
shell.run("command")
favorites.add(site)
warningManager.evaluateWarnings()
container.shell.run("command")
container.favorites.add(site)
}
}
```
@@ -21,7 +20,7 @@ class MyClass {
The `@ContainerAccess` macro automatically adds:
- 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
## Maintenance
@@ -33,8 +32,6 @@ When you add new services to `Container`, you must update the service list in:
```swift
let allContainerServices: [(name: String, type: String)] = [
("shell", "ShellProtocol"),
("favorites", "Favorites"),
("warningManager", "WarningManager"),
// Add your new service here:
// ("myNewService", "MyServiceType"),
]

View File

@@ -2,7 +2,7 @@
///
/// This macro generates:
/// - 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
///
/// Usage:
@@ -12,9 +12,8 @@
/// @ContainerAccess
/// class MyClass {
/// func doSomething() {
/// shell.run("command")
/// favorites.add(site)
/// warningManager.evaluateWarnings()
/// container.shell.run("command")
/// container.favorites.add(site)
/// }
/// }
/// ```

View File

@@ -42,24 +42,13 @@ public struct ContainerAccessMacro: MemberMacro {
if !hasExistingInit {
members.append(
"""
init(container: Container = App.shared.container) {
init(_ 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
}
}

View File

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

View File

@@ -12,7 +12,11 @@ import ContainerMacro
@ContainerAccess
class Actions {
var formulae: HomebrewFormulae {
return HomebrewFormulae()
return HomebrewFormulae(App.shared.container)
}
var paths: Paths {
return container.paths
}
// MARK: - Services
@@ -110,10 +114,10 @@ class Actions {
// MARK: - Other Actions
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
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")!
}
@@ -133,7 +137,7 @@ class Actions {
extensions and/or run `composer global update`.
*/
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.php)", sudo: formulae.php.elevated)
await brew(container, "services restart \(formulae.nginx)", sudo: formulae.nginx.elevated)

View File

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

View File

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

View File

@@ -74,7 +74,7 @@ class ActivePhpInstallation {
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
.split(separator: "\n")
.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.
*/
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"))
@@ -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`.
*/
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
if value == "-1" {

View File

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

View File

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

View File

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

View File

@@ -26,7 +26,7 @@ class InternalSwitcher: PhpSwitcher {
let versions = getVersionsToBeHandled(version)
await withTaskGroup(of: String.self, body: { group in
for available in phpEnvs.availablePhpVersions {
for available in container.phpEnvs.availablePhpVersions {
group.addTask {
await self.unlinkAndStopPhpVersion(available)
return available
@@ -103,7 +103,7 @@ class InternalSwitcher: PhpSwitcher {
if Valet.enabled(feature: .isolatedSites) && primary {
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).")
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,7 @@ import ContainerMacro
@ContainerAccess
class Brew {
static let shared = Brew()
static let shared = Brew(App.shared.container)
/// Formulae that can be observed.
var formulae = BrewFormulaeObservable()
@@ -21,7 +21,7 @@ class Brew {
/// Determine which version of Homebrew is installed.
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)
if let version = version {

View File

@@ -12,7 +12,11 @@ import ContainerMacro
@ContainerAccess
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.
@@ -23,7 +27,7 @@ class BrewDiagnostics {
Load which taps are installed.
*/
public func loadInstalledTaps() async {
installedTaps = await shell
installedTaps = await container.shell
.pipe("\(container.paths.brew) tap")
.out
.split(separator: "\n")
@@ -123,7 +127,7 @@ class BrewDiagnostics {
public func checkForValetMisconfiguration() async {
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.")
return
}
@@ -132,7 +136,7 @@ class BrewDiagnostics {
let primary = install.version.short
// Versions to be handled
let switcher = InternalSwitcher()
let switcher = InternalSwitcher(container)
for version in switcher.getVersionsToBeHandled(primary)
where await switcher.ensureValetConfigurationIsValidForPhpVersion(version) {
@@ -162,7 +166,7 @@ class BrewDiagnostics {
Check if the alias conflict as documented in `checkForCaskConflict` actually occurred.
*/
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 {
Log.info("The user does not appear to have tapped: shivammathur/php")
@@ -181,8 +185,10 @@ class BrewDiagnostics {
+ "This could be a problem!")
Log.info("Determining whether both of these versions are installed...")
let bothInstalled = phpEnvs.availablePhpVersions.contains(tapPhp.version)
&& phpEnvs.availablePhpVersions.contains(PhpEnvironments.brewPhpAlias)
let availablePhpVersions = container.phpEnvs.availablePhpVersions
let bothInstalled = availablePhpVersions.contains(tapPhp.version)
&& availablePhpVersions.contains(PhpEnvironments.brewPhpAlias)
if bothInstalled {
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.
*/
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")
.out

View File

@@ -35,7 +35,7 @@ class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae {
\(container.paths.brew) outdated --json --formulae
"""
let rawJsonText = await shell.pipe(command).out
let rawJsonText = await container.shell.pipe(command).out
.data(using: .utf8)!
outdated = try? JSONDecoder().decode(
OutdatedFormulae.self,
@@ -50,7 +50,7 @@ class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae {
var upgradeVersion: String?
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.isPreRelease ? "\(fullVersion!)-dev" : fullVersion

View File

@@ -68,7 +68,7 @@ class InstallPhpExtensionCommand: BrewCommand {
// Restart PHP-FPM
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

View File

@@ -31,7 +31,7 @@ class RemovePhpExtensionCommand: BrewCommand {
))
// Keep track of the file that contains the information about the extension
let existing = phpEnvs
let existing = container.phpEnvs
.cachedPhpInstallations[phpExtension.phpVersion]?
.extensions.first(where: { ext in
ext.name == phpExtension.name
@@ -64,9 +64,9 @@ class RemovePhpExtensionCommand: BrewCommand {
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()
@@ -81,7 +81,7 @@ class RemovePhpExtensionCommand: BrewCommand {
// 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.")
do {
try filesystem.remove(ext.file)
try container.filesystem.remove(ext.file)
} catch {
Log.err("The file `\(ext.file)` could not be removed.")
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -58,7 +58,7 @@ class ValetSite: ValetListable {
/// Which version of PHP is actually used to serve this site.
var servingPhpVersion: String {
return self.isolatedPhpVersion?.versionNumber.short
?? phpEnvs.phpInstall?.version.short
?? container.phpEnvs.phpInstall?.version.short
?? "???"
}
@@ -107,12 +107,12 @@ class ValetSite: ValetListable {
*/
public func determineIsolated() {
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) "
+ "but that PHP version is unavailable.")
return
}
self.isolatedPhpVersion = phpEnvs.cachedPhpInstallations[version]
self.isolatedPhpVersion = container.phpEnvs.cachedPhpInstallations[version]
} else {
self.isolatedPhpVersion = nil
}
@@ -123,7 +123,10 @@ class ValetSite: ValetListable {
- Note: The file is not validated, only its presence is checked.
*/
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"
do {
if filesystem.fileExists(path) {
if container.filesystem.fileExists(path) {
let decoded = try JSONDecoder().decode(
ComposerJson.self,
from: String(
@@ -216,7 +219,7 @@ class ValetSite: ValetListable {
for (suffix, source) in files {
do {
let path = "\(absolutePath)/\(suffix)"
if filesystem.fileExists(path) {
if container.filesystem.fileExists(path) {
return try self.handleValetFile(path, source)
}
} catch {
@@ -253,7 +256,7 @@ class ValetSite: ValetListable {
return
}
guard let linked = phpEnvs.phpInstall else {
guard let linked = container.phpEnvs.phpInstall else {
self.isCompatibleWithPreferredPhpVersion = false
return
}

View File

@@ -68,8 +68,8 @@ class Valet {
}
lazy var installed: Bool = {
return filesystem.fileExists(container.paths.binPath.appending("/valet"))
&& filesystem.anyExists("~/.config/valet")
return container.filesystem.fileExists(container.paths.binPath.appending("/valet"))
&& container.filesystem.anyExists("~/.config/valet")
}()
/**
@@ -92,7 +92,7 @@ class Valet {
and the app cannot start.
*/
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
if !output.contains("Laravel Valet") {
@@ -122,7 +122,9 @@ class Valet {
do {
config = try JSONDecoder().decode(
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 {
Log.err(error)
@@ -186,7 +188,7 @@ class Valet {
return
}
if phpEnvs.phpInstall == nil {
if container.phpEnvs.phpInstall == nil {
Log.info("Cannot validate Valet version if no PHP version is linked.")
return
}
@@ -209,7 +211,7 @@ class Valet {
Determine if any platform issues are detected when running `valet --version`.
*/
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")
}
@@ -243,7 +245,7 @@ class Valet {
that means that Valet won't work properly.
*/
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")
return true
}
@@ -251,12 +253,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 = "\(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")
}
// 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() {
Task {
await Actions().linkPhp()
await actions.linkPhp()
}
}
@@ -45,7 +45,7 @@ extension MainMenu {
}
asyncExecution {
try Actions().fixHomebrewPermissions()
try self.actions.fixHomebrewPermissions()
} success: {
NVAlert()
.withInformation(
@@ -62,27 +62,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,
@@ -94,7 +94,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,
@@ -129,7 +129,7 @@ extension MainMenu {
}
do {
var modes = Xdebug().activeModes
var modes = Xdebug(container).activeModes
if let index = modes.firstIndex(of: sender.mode) {
modes.remove(at: index)
@@ -157,7 +157,7 @@ extension MainMenu {
await sender.phpExtension?.toggle()
if Preferences.isEnabled(.autoServiceRestartAfterExtensionToggle) {
await Actions().restartPhpFpm()
await actions.restartPhpFpm()
}
}
}
@@ -212,14 +212,14 @@ extension MainMenu {
@objc func openPhpInfo() {
asyncWithBusyUI {
Task { // Create temporary file and open the URL
let url = await Actions().createTempPhpInfoFile()
let url = await self.actions.createTempPhpInfoFile()
NSWorkspace.shared.open(url)
}
}
}
@MainActor @objc func updateGlobalComposerDependencies() {
ComposerWindow().updateGlobalDependencies(
ComposerWindow(container).updateGlobalDependencies(
notify: true,
completion: { _ in }
)
@@ -232,23 +232,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(container).fixMyValet()
if previousVersion == PhpEnvironments.brewPhpAlias || previousVersion == nil {
self.presentAlertForSameVersion()

View File

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

View File

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

View File

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

View File

@@ -83,7 +83,7 @@ struct Preset: Codable, Equatable {
if self.version != nil {
if await !switchToPhpVersionIfValid() {
PresetHelper.rollbackPreset = nil
await Actions().restartPhpFpm()
await Actions(container).restartPhpFpm()
return
}
}
@@ -111,7 +111,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(container).restartPhpFpm()
Task { @MainActor in
// Show the correct notification

View File

@@ -16,7 +16,7 @@ class InstallHomebrew {
"$(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)
}, 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.
*/
private func add(_ text: String) async -> Bool {
let outcome = await shell.pipe("""
let outcome = await container.shell.pipe("""
touch ~/.zshrc && \
grep -qxF '\(text)' ~/.zshrc \
|| echo '\n\n\(text)\n' >> ~/.zshrc

View File

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

View File

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

View File

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

View File

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