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

♻️ Get rid of ContainerMacro

This commit is contained in:
2025-10-28 13:16:30 +01:00
parent 8eca1a55b5
commit 16522ddc60
39 changed files with 263 additions and 471 deletions

View File

@@ -3,11 +3,10 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 60; objectVersion = 54;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
0303412A2E92C3560031BE17 /* ContainerMacro in Frameworks */ = {isa = PBXBuildFile; productRef = 030341292E92C3560031BE17 /* ContainerMacro */; };
0309E6672B0D4B2F002AC007 /* BrewExtensionsObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0309E6662B0D4B2F002AC007 /* BrewExtensionsObservable.swift */; }; 0309E6672B0D4B2F002AC007 /* BrewExtensionsObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0309E6662B0D4B2F002AC007 /* BrewExtensionsObservable.swift */; };
031E2B692B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; }; 031E2B692B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; };
031E2B6A2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; }; 031E2B6A2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; };
@@ -1295,7 +1294,6 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
0303412A2E92C3560031BE17 /* ContainerMacro in Frameworks */,
C47014FF2C46D57C0069AAE7 /* NVAlert in Frameworks */, C47014FF2C46D57C0069AAE7 /* NVAlert in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -2432,7 +2430,6 @@
name = "PHP Monitor"; name = "PHP Monitor";
packageProductDependencies = ( packageProductDependencies = (
C47014FE2C46D57C0069AAE7 /* NVAlert */, C47014FE2C46D57C0069AAE7 /* NVAlert */,
030341292E92C3560031BE17 /* ContainerMacro */,
); );
productName = phpmon; productName = phpmon;
productReference = C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */; productReference = C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */;
@@ -2550,7 +2547,6 @@
packageReferences = ( packageReferences = (
C47014FA2C46D31B0069AAE7 /* XCRemoteSwiftPackageReference "NVAppUpdater" */, C47014FA2C46D31B0069AAE7 /* XCRemoteSwiftPackageReference "NVAppUpdater" */,
C47014FD2C46D57C0069AAE7 /* XCRemoteSwiftPackageReference "NVAlert" */, C47014FD2C46D57C0069AAE7 /* XCRemoteSwiftPackageReference "NVAlert" */,
030341282E92C3560031BE17 /* XCLocalSwiftPackageReference "packages/container-macro" */,
); );
productRefGroup = C41C1B3422B0097F00E7CF16 /* Products */; productRefGroup = C41C1B3422B0097F00E7CF16 /* Products */;
projectDirPath = ""; projectDirPath = "";
@@ -4505,13 +4501,6 @@
}; };
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
030341282E92C3560031BE17 /* XCLocalSwiftPackageReference "packages/container-macro" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = "packages/container-macro";
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
C47014FA2C46D31B0069AAE7 /* XCRemoteSwiftPackageReference "NVAppUpdater" */ = { C47014FA2C46D31B0069AAE7 /* XCRemoteSwiftPackageReference "NVAppUpdater" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
@@ -4532,10 +4521,6 @@
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
030341292E92C3560031BE17 /* ContainerMacro */ = {
isa = XCSwiftPackageProductDependency;
productName = ContainerMacro;
};
C47014FB2C46D31B0069AAE7 /* NVAppUpdater */ = { C47014FB2C46D31B0069AAE7 /* NVAppUpdater */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = C47014FA2C46D31B0069AAE7 /* XCRemoteSwiftPackageReference "NVAppUpdater" */; package = C47014FA2C46D31B0069AAE7 /* XCRemoteSwiftPackageReference "NVAppUpdater" */;

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2600"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ContainerMacro"
BuildableName = "ContainerMacro"
BlueprintName = "ContainerMacro"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ContainerMacro"
BuildableName = "ContainerMacro"
BlueprintName = "ContainerMacro"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>ContainerMacro.xcscheme_^#shared#^_</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>4</integer>
</dict>
<key>NVContainer.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>ContainerMacro</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

View File

@@ -1,38 +0,0 @@
// swift-tools-version: 5.9
import PackageDescription
import CompilerPluginSupport
let package = Package(
name: "ContainerMacro",
platforms: [.macOS(.v13)],
products: [
.library(
name: "ContainerMacro",
targets: ["ContainerMacro"]
),
],
dependencies: [
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"),
],
targets: [
.macro(
name: "ContainerMacroPlugin",
dependencies: [
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
]
),
.target(
name: "ContainerMacro",
dependencies: ["ContainerMacroPlugin"]
),
.testTarget(
name: "ContainerMacroTests",
dependencies: [
"ContainerMacroPlugin",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
]
),
]
)

View File

@@ -1,52 +0,0 @@
# ContainerMacro
A Swift macro for automatic container dependency injection in PHP Monitor.
## Usage
```swift
import ContainerMacro
@ContainerAccess
class MyClass {
func doSomething() {
container.shell.run("command")
container.favorites.add(site)
}
}
```
## What it generates
The `@ContainerAccess` macro automatically adds:
- A private `container: Container` property
- An `init(_ container:)` initializer
- Computed properties for each Container service you want to access
## Maintenance
When you add new services to `Container`, you must update the service list in:
**`Sources/ContainerMacroPlugin/ContainerAccessMacro.swift`** (lines 14-18):
```swift
let allContainerServices: [(name: String, type: String)] = [
("shell", "ShellProtocol"),
// Add your new service here:
// ("myNewService", "MyServiceType"),
]
```
## Testing
Run tests with:
```bash
cd packages/container-macro
swift test
```
## Integration
The package is added as a local Swift Package in Xcode:
- File → Add Package Dependencies → Add Local...
- Select `packages/container-macro`

View File

@@ -1,24 +0,0 @@
/// Automatically adds container dependency injection to a class.
///
/// This macro generates:
/// - A public `container` property
/// - An `init(_ container:)` initializer
/// - Computed properties for all Container services
///
/// Usage:
/// ```swift
/// import ContainerMacro
///
/// @ContainerAccess
/// class MyClass {
/// func doSomething() {
/// container.shell.run("command")
/// container.favorites.add(site)
/// }
/// }
/// ```
@attached(member, names: named(container), named(init(container:)), arbitrary)
public macro ContainerAccess() = #externalMacro(
module: "ContainerMacroPlugin",
type: "ContainerAccessMacro"
)

View File

@@ -1,61 +0,0 @@
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros
public struct ContainerAccessMacro: MemberMacro {
public static func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
// Map of ALL Container properties to their types
// This should be kept in sync with the Container class
let allContainerServices: [(name: String, type: String)] = [
("shell", "ShellProtocol"),
("filesystem", "FileSystemProtocol"),
("command", "CommandProtocol"),
("paths", "Paths"),
("phpEnvs", "PhpEnvironments"),
("favorites", "Favorites"),
("warningManager", "WarningManager")
]
// Check if the class already has an initializer
let hasExistingInit = declaration.memberBlock.members.contains { member in
if let initDecl = member.decl.as(InitializerDeclSyntax.self) {
return true
}
return false
}
var members: [DeclSyntax] = []
// Add the container property
members.append(
"""
public let container: Container
"""
)
// Only add the initializer if one doesn't already exist
if !hasExistingInit {
members.append(
"""
init(_ container: Container) {
self.container = container
}
"""
)
}
return members
}
}
@main
struct ContainerMacroPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
ContainerAccessMacro.self,
]
}

View File

@@ -1,106 +0,0 @@
import SwiftSyntaxMacros
import SwiftSyntaxMacrosTestSupport
import XCTest
#if canImport(ContainerMacroPlugin)
import ContainerMacroPlugin
final class ContainerAccessMacroTests: XCTestCase {
let testMacros: [String: Macro.Type] = [
"ContainerAccess": ContainerAccessMacro.self,
]
func testContainerAccessWithSpecificServices() throws {
assertMacroExpansion(
"""
@ContainerAccess(["shell"])
class InternalSwitcher {
func doSomething() {
print("Hello")
}
}
""",
expandedSource: """
class InternalSwitcher {
func doSomething() {
print("Hello")
}
private let container: Container
init(container: Container = App.shared.container) {
self.container = container
}
private var shell: ShellProtocol {
return container.shell
}
}
""",
macros: testMacros
)
}
func testContainerAccessWithMultipleServices() throws {
assertMacroExpansion(
"""
@ContainerAccess(["shell", "favorites"])
class MyClass {
}
""",
expandedSource: """
class MyClass {
private let container: Container
init(container: Container = App.shared.container) {
self.container = container
}
private var shell: ShellProtocol {
return container.shell
}
private var favorites: Favorites {
return container.favorites
}
}
""",
macros: testMacros
)
}
func testContainerAccessWithAllServices() throws {
assertMacroExpansion(
"""
@ContainerAccess
class MyClass {
}
""",
expandedSource: """
class MyClass {
private let container: Container
init(container: Container = App.shared.container) {
self.container = container
}
private var shell: ShellProtocol {
return container.shell
}
private var favorites: Favorites {
return container.favorites
}
private var warningManager: WarningManager {
return container.warningManager
}
}
""",
macros: testMacros
)
}
}
#endif

View File

@@ -7,10 +7,19 @@
import Foundation import Foundation
import AppKit import AppKit
import ContainerMacro
@ContainerAccess
class Actions { class Actions {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Variables
var formulae: HomebrewFormulae { var formulae: HomebrewFormulae {
return HomebrewFormulae(App.shared.container) return HomebrewFormulae(App.shared.container)
} }

View File

@@ -7,10 +7,19 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
struct HomebrewFormulae { struct HomebrewFormulae {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Variables
var php: HomebrewFormula { var php: HomebrewFormula {
if container.phpEnvs.homebrewPackage == nil { if container.phpEnvs.homebrewPackage == nil {
return HomebrewFormula("php", elevated: true) return HomebrewFormula("php", elevated: true)

View File

@@ -21,6 +21,9 @@ extension String {
} }
class RealFileSystem: FileSystemProtocol { class RealFileSystem: FileSystemProtocol {
// MARK: - Container
var container: Container var container: Container
init(container: Container) { init(container: Container) {

View File

@@ -7,17 +7,22 @@
// //
import Foundation import Foundation
import ContainerMacro
/// An application that is capable of opening a particular directory (usually of a PHP project). /// An application that is capable of opening a particular directory (usually of a PHP project).
/// In most cases this is going to be a code editor, but it could also be another application /// In most cases this is going to be a code editor, but it could also be another application
/// that supports opening those directories, like a visual Git client or a terminal app. /// that supports opening those directories, like a visual Git client or a terminal app.
@ContainerAccess
class Application { class Application {
enum AppType { enum AppType {
case editor, browser, git_gui, terminal, user_supplied case editor, browser, git_gui, terminal, user_supplied
} }
// MARK: - Container
var container: Container
// MARK: - Variables
/// Name of the app. Used for display purposes and to determine `name.app` exists. /// Name of the app. Used for display purposes and to determine `name.app` exists.
let name: String let name: String

View File

@@ -6,7 +6,6 @@
// //
import Foundation import Foundation
import ContainerMacro
/** /**
An installed version of PHP, that was detected by scanning the `/opt/php@version/bin` directory. An installed version of PHP, that was detected by scanning the `/opt/php@version/bin` directory.
@@ -18,22 +17,27 @@ import ContainerMacro
Using `version.short` is advisable if you want to interact with Homebrew. Using `version.short` is advisable if you want to interact with Homebrew.
*/ */
@ContainerAccess
class ActivePhpInstallation { class ActivePhpInstallation {
// MARK: - Container
var container: Container
// MARK: - Variables
var version: VersionNumber! var version: VersionNumber!
var limits: Limits! var limits: Limits!
var iniFiles: [PhpConfigurationFile] = [] var iniFiles: [PhpConfigurationFile] = []
var hasErrorState: Bool = false var hasErrorState: Bool = false
// MARK: - Computed
var extensions: [PhpExtension] { var extensions: [PhpExtension] {
return iniFiles.flatMap { initFile in return iniFiles.flatMap { initFile in
return initFile.extensions return initFile.extensions
} }
} }
// MARK: - Computed
var formula: String { var formula: String {
return (version.short == PhpEnvironments.brewPhpAlias) ? "php" : "php@\(version.short)" return (version.short == PhpEnvironments.brewPhpAlias) ? "php" : "php@\(version.short)"
} }

View File

@@ -8,10 +8,19 @@
import Foundation import Foundation
import Cocoa import Cocoa
import ContainerMacro
@ContainerAccess
class Xdebug { class Xdebug {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Variables
public var enabled: Bool { public var enabled: Bool {
return container.phpEnvs.getConfigFile(forKey: "xdebug.mode") != nil return container.phpEnvs.getConfigFile(forKey: "xdebug.mode") != nil
} }
@@ -28,6 +37,19 @@ class Xdebug {
return value.components(separatedBy: ",").filter { self.availableModes.contains($0) } return value.components(separatedBy: ",").filter { self.availableModes.contains($0) }
} }
public var availableModes: [String] {
return [
"develop",
"coverage",
"debug",
"gcstats",
"profile",
"trace"
]
}
// MARK: - Methods
public func asMenuItems() -> [NSMenuItem] { public func asMenuItems() -> [NSMenuItem] {
var items: [NSMenuItem] = [] var items: [NSMenuItem] = []
@@ -46,15 +68,4 @@ class Xdebug {
return items return items
} }
public var availableModes: [String] {
return [
"develop",
"coverage",
"debug",
"gcstats",
"profile",
"trace"
]
}
} }

View File

@@ -7,7 +7,6 @@
// //
import Foundation import Foundation
import ContainerMacro
/** /**
A PHP extension that was detected in the php.ini file. A PHP extension that was detected in the php.ini file.
@@ -16,8 +15,14 @@ import ContainerMacro
- Note: You need to know more about regular expressions to be able to deal with these NSRegularExpression - Note: You need to know more about regular expressions to be able to deal with these NSRegularExpression
instances. You can find more information here: https://nshipster.com/swift-regular-expressions/ instances. You can find more information here: https://nshipster.com/swift-regular-expressions/
*/ */
@ContainerAccess
class PhpExtension { class PhpExtension {
// MARK: - Container
var container: Container
// MARK: - Variables
/// The file where this extension was located. /// The file where this extension was located.
var file: String var file: String

View File

@@ -7,10 +7,15 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class PhpInstallation { class PhpInstallation {
// MARK: - Container
var container: Container
// MARK: - Variables
var versionNumber: VersionNumber var versionNumber: VersionNumber
var iniFiles: [PhpConfigurationFile] = [] var iniFiles: [PhpConfigurationFile] = []
@@ -35,6 +40,8 @@ class PhpInstallation {
return "php@\(self.versionNumber.short)" return "php@\(self.versionNumber.short)"
} }
// MARK: - Methods
/** /**
In order to determine details about a PHP installation, In order to determine details about a PHP installation,
well simply run `php-config --version` in the relevant directory. well simply run `php-config --version` in the relevant directory.

View File

@@ -7,10 +7,19 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class InternalSwitcher: PhpSwitcher { class InternalSwitcher: PhpSwitcher {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Switcher
/** /**
Switching to a new PHP version involves: Switching to a new PHP version involves:
- unlinking the current version - unlinking the current version

View File

@@ -8,10 +8,11 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
import ContainerMacro
@ContainerAccess
class ServicesManager: ObservableObject { class ServicesManager: ObservableObject {
var container: Container
@ObservedObject static var shared: ServicesManager = ValetServicesManager(App.shared.container) @ObservedObject static var shared: ServicesManager = ValetServicesManager(App.shared.container)
@Published var services = [Service]() @Published var services = [Service]()

View File

@@ -9,9 +9,9 @@
import Foundation import Foundation
import Cocoa import Cocoa
import NVAlert import NVAlert
import ContainerMacro
class ValetServicesManager: ServicesManager { class ValetServicesManager: ServicesManager {
override init(_ container: Container) { override init(_ container: Container) {
super.init(container) super.init(container)

View File

@@ -8,14 +8,25 @@
import Foundation import Foundation
import NVAlert import NVAlert
import ContainerMacro
@ContainerAccess
@MainActor class ComposerWindow { @MainActor class ComposerWindow {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Variables
private var shouldNotify: Bool! = nil private var shouldNotify: Bool! = nil
private var completion: ((Bool) -> Void)! = nil private var completion: ((Bool) -> Void)! = nil
private var window: TerminalProgressWindowController? private var window: TerminalProgressWindowController?
// MARK: - Methods
/** /**
Updates the global dependencies and runs the completion callback when done. Updates the global dependencies and runs the completion callback when done.
*/ */

View File

@@ -7,10 +7,19 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class BrewPermissionFixer { class BrewPermissionFixer {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Variables
var broken: [DueOwnershipFormula] = [] var broken: [DueOwnershipFormula] = []
/** /**

View File

@@ -7,10 +7,19 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class Brew { class Brew {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Variables
static let shared = Brew(App.shared.container) static let shared = Brew(App.shared.container)
/// Formulae that can be observed. /// Formulae that can be observed.

View File

@@ -8,12 +8,23 @@
import Foundation import Foundation
import NVAlert import NVAlert
import ContainerMacro
@ContainerAccess
class BrewDiagnostics { class BrewDiagnostics {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Static Instance
public static let shared = BrewDiagnostics(App.shared.container) public static let shared = BrewDiagnostics(App.shared.container)
// MARK: - Variables
var filesystem: FileSystemProtocol { var filesystem: FileSystemProtocol {
return container.filesystem return container.filesystem
} }
@@ -23,6 +34,8 @@ class BrewDiagnostics {
*/ */
public var installedTaps: [String] = [] public var installedTaps: [String] = []
// MARK: - Methods
/** /**
Load which taps are installed. Load which taps are installed.
*/ */

View File

@@ -7,9 +7,9 @@
// //
import Foundation import Foundation
import ContainerMacro
struct BrewPhpFormula: Equatable { struct BrewPhpFormula: Equatable {
/// The dependency container. /// The dependency container.
let container: Container let container: Container

View File

@@ -7,7 +7,6 @@
// //
import Foundation import Foundation
import ContainerMacro
protocol HandlesBrewPhpFormulae { protocol HandlesBrewPhpFormulae {
func loadPhpVersions(loadOutdated: Bool) async -> [BrewPhpFormula] func loadPhpVersions(loadOutdated: Bool) async -> [BrewPhpFormula]
@@ -24,8 +23,17 @@ extension HandlesBrewPhpFormulae {
} }
} }
@ContainerAccess
class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae { class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Methods
public func loadPhpVersions(loadOutdated: Bool) async -> [BrewPhpFormula] { public func loadPhpVersions(loadOutdated: Bool) async -> [BrewPhpFormula] {
var outdated: [OutdatedFormula]? var outdated: [OutdatedFormula]?

View File

@@ -7,10 +7,15 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class InstallPhpExtensionCommand: BrewCommand { class InstallPhpExtensionCommand: BrewCommand {
// MARK: - Container
var container: Container
// MARK: - Variables
let installing: [BrewPhpExtension] let installing: [BrewPhpExtension]
func getExtensionNames() -> String { func getExtensionNames() -> String {
@@ -21,6 +26,8 @@ class InstallPhpExtensionCommand: BrewCommand {
return "phpman.steps.installing".localized(getExtensionNames()) return "phpman.steps.installing".localized(getExtensionNames())
} }
// MARK: - Methods
public init(_ container: Container, public init(_ container: Container,
install extensions: [BrewPhpExtension]) { install extensions: [BrewPhpExtension]) {
self.container = container self.container = container

View File

@@ -7,12 +7,19 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class RemovePhpExtensionCommand: BrewCommand { class RemovePhpExtensionCommand: BrewCommand {
// MARK: - Container
var container: Container
// MARK: - Variables
public let phpExtension: BrewPhpExtension public let phpExtension: BrewPhpExtension
// MARK: - Methods
public init(_ container: Container, public init(_ container: Container,
remove formula: BrewPhpExtension) { remove formula: BrewPhpExtension) {
self.container = container self.container = container

View File

@@ -7,15 +7,22 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class ModifyPhpVersionCommand: BrewCommand { class ModifyPhpVersionCommand: BrewCommand {
// MARK: - Container
var container: Container
// MARK: - Variables
let title: String let title: String
let installing: [BrewPhpFormula] let installing: [BrewPhpFormula]
let upgrading: [BrewPhpFormula] let upgrading: [BrewPhpFormula]
let phpGuard: PhpGuard let phpGuard: PhpGuard
// MARK: - Methods
func getCommandTitle() -> String { func getCommandTitle() -> String {
return title return title
} }

View File

@@ -7,14 +7,21 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class RemovePhpVersionCommand: BrewCommand { class RemovePhpVersionCommand: BrewCommand {
// MARK: - Container
var container: Container
// MARK: - Variables
let formula: String let formula: String
let version: String let version: String
let phpGuard: PhpGuard let phpGuard: PhpGuard
// MARK: - Methods
init( init(
_ container: Container, _ container: Container,
formula: String formula: String

View File

@@ -7,15 +7,24 @@
// //
import Foundation import Foundation
import ContainerMacro
struct ValetInteractionError: Error { struct ValetInteractionError: Error {
/// The command the user should try (and failed). /// The command the user should try (and failed).
var command: String var command: String
} }
@ContainerAccess
class ValetInteractor { class ValetInteractor {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Shared Instance
static var shared = ValetInteractor(App.shared.container) static var shared = ValetInteractor(App.shared.container)
public static func useFake() { public static func useFake() {

View File

@@ -7,11 +7,17 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class ValetDomainScanner: DomainScanner { class ValetDomainScanner: DomainScanner {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Sites // MARK: - Sites
func resolveSiteCount(paths: [String]) -> Int { func resolveSiteCount(paths: [String]) -> Int {

View File

@@ -7,10 +7,12 @@
// //
import Foundation import Foundation
import ContainerMacro
@ContainerAccess
class ValetSite: ValetListable { class ValetSite: ValetListable {
/// Dependency container.
var container: Container
/// Name of the site. Does not include the TLD. /// Name of the site. Does not include the TLD.
var name: String var name: String

View File

@@ -7,14 +7,12 @@
// //
import Foundation import Foundation
import ContainerMacro
/** /**
This class is responsible for handling the state of Valet throughout PHP Monitor. A singleton instance is created This class is responsible for handling the state of Valet throughout PHP Monitor. A singleton instance is created
and accessible throughout the lifecycle of the app, unless the user has decided to not use Valet. In that case, and accessible throughout the lifecycle of the app, unless the user has decided to not use Valet. In that case,
only a restricted subset of functionality is available in the app. only a restricted subset of functionality is available in the app.
*/ */
@ContainerAccess
class Valet { class Valet {
enum FeatureFlag { enum FeatureFlag {
@@ -23,6 +21,9 @@ class Valet {
static let shared = Valet() static let shared = Valet()
/// The dependency container.
var container: Container
/// The version of Valet that was detected. /// The version of Valet that was detected.
var version: VersionNumber? var version: VersionNumber?

View File

@@ -6,10 +6,21 @@
// Copyright © 2025 Nico Verbruggen. All rights reserved. // Copyright © 2025 Nico Verbruggen. All rights reserved.
// //
import ContainerMacro ///
/// This class is still WIP and pending for a future release of PHP Monitor.
@ContainerAccess ///
class InstallHomebrew { class InstallHomebrew {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Methods
public func run() async throws { public func run() async throws {
let script = """ let script = """
NONINTERACTIVE=1 /bin/bash -c \ NONINTERACTIVE=1 /bin/bash -c \

View File

@@ -6,10 +6,18 @@
// Copyright © 2025 Nico Verbruggen. All rights reserved. // Copyright © 2025 Nico Verbruggen. All rights reserved.
// //
import ContainerMacro
@ContainerAccess
class ZshRunCommand { class ZshRunCommand {
// MARK: - Container
var container: Container
init(_ container: Container) {
self.container = container
}
// MARK: - Methods
/** /**
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.
*/ */

View File

@@ -7,9 +7,9 @@
// //
import Foundation import Foundation
import ContainerMacro
class BytePhpPreference: PhpPreference { class BytePhpPreference: PhpPreference {
enum UnitOption: String, CaseIterable { enum UnitOption: String, CaseIterable {
case kilobyte = "K" case kilobyte = "K"
case megabyte = "M" case megabyte = "M"

View File

@@ -8,10 +8,11 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
import ContainerMacro
@ContainerAccess
class PhpPreference { class PhpPreference {
var container: Container
let key: String let key: String
init(_ container: Container, key: String) { init(_ container: Container, key: String) {

View File

@@ -7,19 +7,18 @@
// //
import Foundation import Foundation
import ContainerMacro
struct FileExistenceCheck {
let condition: (() -> Bool)?
let path: String
}
@ContainerAccess
class PhpConfigChecker { class PhpConfigChecker {
public static var shared = PhpConfigChecker(App.shared.container) public static var shared = PhpConfigChecker(App.shared.container)
var missing: [String] = [] var missing: [String] = []
var container: Container
init(_ container: Container) {
self.container = container
}
public func check() { public func check() {
missing = [] missing = []
@@ -49,3 +48,8 @@ class PhpConfigChecker {
} }
} }
} }
struct FileExistenceCheck {
let condition: (() -> Bool)?
let path: String
}

View File

@@ -8,10 +8,11 @@
import Foundation import Foundation
import Cocoa import Cocoa
import ContainerMacro
@ContainerAccess
class WarningManager: ObservableObject { class WarningManager: ObservableObject {
var container: Container
init( init(
container: Container, container: Container,
fake: Bool = false fake: Bool = false