mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2026-03-30 00:20:08 +02:00
♻️ All unit tests pass w/ DI container
This commit is contained in:
@@ -13,6 +13,10 @@
|
|||||||
031E2B6A2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; };
|
031E2B6A2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; };
|
||||||
031E2B6B2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; };
|
031E2B6B2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; };
|
||||||
031E2B6C2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; };
|
031E2B6C2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; };
|
||||||
|
031F24802EA1071A00CFB8D9 /* Container+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031F247F2EA1071700CFB8D9 /* Container+Fake.swift */; };
|
||||||
|
031F24812EA1071A00CFB8D9 /* Container+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031F247F2EA1071700CFB8D9 /* Container+Fake.swift */; };
|
||||||
|
031F24822EA1071A00CFB8D9 /* Container+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031F247F2EA1071700CFB8D9 /* Container+Fake.swift */; };
|
||||||
|
031F24832EA1071A00CFB8D9 /* Container+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031F247F2EA1071700CFB8D9 /* Container+Fake.swift */; };
|
||||||
03263A382E86D5EC00BD0415 /* UpdateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03263A372E86D5E800BD0415 /* UpdateScheduler.swift */; };
|
03263A382E86D5EC00BD0415 /* UpdateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03263A372E86D5E800BD0415 /* UpdateScheduler.swift */; };
|
||||||
03263A392E86D5EC00BD0415 /* UpdateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03263A372E86D5E800BD0415 /* UpdateScheduler.swift */; };
|
03263A392E86D5EC00BD0415 /* UpdateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03263A372E86D5E800BD0415 /* UpdateScheduler.swift */; };
|
||||||
03263A3A2E86D5EC00BD0415 /* UpdateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03263A372E86D5E800BD0415 /* UpdateScheduler.swift */; };
|
03263A3A2E86D5EC00BD0415 /* UpdateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03263A372E86D5E800BD0415 /* UpdateScheduler.swift */; };
|
||||||
@@ -975,6 +979,8 @@
|
|||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
0309E6662B0D4B2F002AC007 /* BrewExtensionsObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewExtensionsObservable.swift; sourceTree = "<group>"; };
|
0309E6662B0D4B2F002AC007 /* BrewExtensionsObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewExtensionsObservable.swift; sourceTree = "<group>"; };
|
||||||
031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewPhpExtension.swift; sourceTree = "<group>"; };
|
031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewPhpExtension.swift; sourceTree = "<group>"; };
|
||||||
|
031F247F2EA1071700CFB8D9 /* Container+Fake.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Container+Fake.swift"; sourceTree = "<group>"; };
|
||||||
|
031F24842EA1132300CFB8D9 /* PHP Monitor.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "PHP Monitor.xctestplan"; sourceTree = "<group>"; };
|
||||||
03263A372E86D5E800BD0415 /* UpdateScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateScheduler.swift; sourceTree = "<group>"; };
|
03263A372E86D5E800BD0415 /* UpdateScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateScheduler.swift; sourceTree = "<group>"; };
|
||||||
0329A9A02E92A2A800A62A12 /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = "<group>"; };
|
0329A9A02E92A2A800A62A12 /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = "<group>"; };
|
||||||
0329A9A22E92A68B00A62A12 /* WarningManager+Evaluations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WarningManager+Evaluations.swift"; sourceTree = "<group>"; };
|
0329A9A22E92A68B00A62A12 /* WarningManager+Evaluations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WarningManager+Evaluations.swift"; sourceTree = "<group>"; };
|
||||||
@@ -1609,6 +1615,7 @@
|
|||||||
C41C1B3522B0097F00E7CF16 /* phpmon */ = {
|
C41C1B3522B0097F00E7CF16 /* phpmon */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
031F247F2EA1071700CFB8D9 /* Container+Fake.swift */,
|
||||||
0329A9A02E92A2A800A62A12 /* Container.swift */,
|
0329A9A02E92A2A800A62A12 /* Container.swift */,
|
||||||
C4B5853A2770FE2500DA4FBE /* Common */,
|
C4B5853A2770FE2500DA4FBE /* Common */,
|
||||||
C41E181722CB61EB0072CF09 /* Domain */,
|
C41E181722CB61EB0072CF09 /* Domain */,
|
||||||
@@ -1967,6 +1974,7 @@
|
|||||||
C471E79628F9B4260021E251 /* tests */ = {
|
C471E79628F9B4260021E251 /* tests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
031F24842EA1132300CFB8D9 /* PHP Monitor.xctestplan */,
|
||||||
C4E2E86828FC2FF2003B070C /* Shared */,
|
C4E2E86828FC2FF2003B070C /* Shared */,
|
||||||
C4F7807A25D7F84B000DBC97 /* unit */,
|
C4F7807A25D7F84B000DBC97 /* unit */,
|
||||||
C471E7AE28F9B4940021E251 /* feature */,
|
C471E7AE28F9B4940021E251 /* feature */,
|
||||||
@@ -2848,6 +2856,7 @@
|
|||||||
C485707028BF452300539B36 /* PhpDoctorWindowController.swift in Sources */,
|
C485707028BF452300539B36 /* PhpDoctorWindowController.swift in Sources */,
|
||||||
C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */,
|
C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */,
|
||||||
C40D725A2A018ACC0054A067 /* BusyStatus.swift in Sources */,
|
C40D725A2A018ACC0054A067 /* BusyStatus.swift in Sources */,
|
||||||
|
031F24802EA1071A00CFB8D9 /* Container+Fake.swift in Sources */,
|
||||||
C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */,
|
C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */,
|
||||||
C4FACE83288F1F9700FC478F /* OnboardingWindowController.swift in Sources */,
|
C4FACE83288F1F9700FC478F /* OnboardingWindowController.swift in Sources */,
|
||||||
C4415E8D2B0287E90035F520 /* BrewFormulaeObservable.swift in Sources */,
|
C4415E8D2B0287E90035F520 /* BrewFormulaeObservable.swift in Sources */,
|
||||||
@@ -2956,6 +2965,7 @@
|
|||||||
C471E85A28F9BB650021E251 /* DomainListTypeCell.swift in Sources */,
|
C471E85A28F9BB650021E251 /* DomainListTypeCell.swift in Sources */,
|
||||||
C471E85B28F9BB650021E251 /* DomainListKindCell.swift in Sources */,
|
C471E85B28F9BB650021E251 /* DomainListKindCell.swift in Sources */,
|
||||||
C4611E5E2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */,
|
C4611E5E2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */,
|
||||||
|
031F24822EA1071A00CFB8D9 /* Container+Fake.swift in Sources */,
|
||||||
C4BF56AD2949381100379603 /* FakeValetInteractor.swift in Sources */,
|
C4BF56AD2949381100379603 /* FakeValetInteractor.swift in Sources */,
|
||||||
C471E85C28F9BB650021E251 /* DomainListWindowController.swift in Sources */,
|
C471E85C28F9BB650021E251 /* DomainListWindowController.swift in Sources */,
|
||||||
C471E85D28F9BB650021E251 /* DomainListVC.swift in Sources */,
|
C471E85D28F9BB650021E251 /* DomainListVC.swift in Sources */,
|
||||||
@@ -3255,6 +3265,7 @@
|
|||||||
C471E7FC28F9BACE0021E251 /* HomebrewDecodable.swift in Sources */,
|
C471E7FC28F9BACE0021E251 /* HomebrewDecodable.swift in Sources */,
|
||||||
C4BB393C2981AFC700F8E797 /* PhpVersionSource.swift in Sources */,
|
C4BB393C2981AFC700F8E797 /* PhpVersionSource.swift in Sources */,
|
||||||
C471E7F628F9BAC80021E251 /* PhpHelper.swift in Sources */,
|
C471E7F628F9BAC80021E251 /* PhpHelper.swift in Sources */,
|
||||||
|
031F24812EA1071A00CFB8D9 /* Container+Fake.swift in Sources */,
|
||||||
039E1D7B2E5F0F300072D13D /* ValetUpgrader.swift in Sources */,
|
039E1D7B2E5F0F300072D13D /* ValetUpgrader.swift in Sources */,
|
||||||
C471E7EE28F9BAC30021E251 /* Constants.swift in Sources */,
|
C471E7EE28F9BAC30021E251 /* Constants.swift in Sources */,
|
||||||
C40934A0298EE8E900D25014 /* AppUpdater.swift in Sources */,
|
C40934A0298EE8E900D25014 /* AppUpdater.swift in Sources */,
|
||||||
@@ -3419,6 +3430,7 @@
|
|||||||
C4EED88A27A48778006D7272 /* InterAppHandler.swift in Sources */,
|
C4EED88A27A48778006D7272 /* InterAppHandler.swift in Sources */,
|
||||||
C4159AF728E4D40400545349 /* RealShellTest.swift in Sources */,
|
C4159AF728E4D40400545349 /* RealShellTest.swift in Sources */,
|
||||||
C450C8C728C919EC002A2B4B /* PreferenceName.swift in Sources */,
|
C450C8C728C919EC002A2B4B /* PreferenceName.swift in Sources */,
|
||||||
|
031F24832EA1071A00CFB8D9 /* Container+Fake.swift in Sources */,
|
||||||
C40D725B2A018ACC0054A067 /* BusyStatus.swift in Sources */,
|
C40D725B2A018ACC0054A067 /* BusyStatus.swift in Sources */,
|
||||||
032DAC292E8BEB5B0018E01C /* RealApi.swift in Sources */,
|
032DAC292E8BEB5B0018E01C /* RealApi.swift in Sources */,
|
||||||
C48D6C75279CD3E400F26D7E /* PhpVersionNumberTest.swift in Sources */,
|
C48D6C75279CD3E400F26D7E /* PhpVersionNumberTest.swift in Sources */,
|
||||||
|
|||||||
@@ -26,11 +26,16 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
shouldAutocreateTestPlan = "YES">
|
<TestPlans>
|
||||||
|
<TestPlanReference
|
||||||
|
reference = "container:tests/PHP Monitor.xctestplan"
|
||||||
|
default = "YES">
|
||||||
|
</TestPlanReference>
|
||||||
|
</TestPlans>
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
skipped = "NO">
|
skipped = "YES">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "C4F7807825D7F84B000DBC97"
|
BlueprintIdentifier = "C4F7807825D7F84B000DBC97"
|
||||||
@@ -40,7 +45,7 @@
|
|||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
skipped = "NO"
|
skipped = "YES"
|
||||||
parallelizable = "YES">
|
parallelizable = "YES">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
|
|||||||
@@ -18,30 +18,30 @@ class Actions {
|
|||||||
// MARK: - Services
|
// MARK: - Services
|
||||||
|
|
||||||
public func linkPhp() async {
|
public func linkPhp() async {
|
||||||
await brew("link php --overwrite --force")
|
await brew(container, "link php --overwrite --force")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func restartPhpFpm() async {
|
public func restartPhpFpm() async {
|
||||||
await brew("services restart \(formulae.php)", sudo: formulae.php.elevated)
|
await brew(container, "services restart \(formulae.php)", sudo: formulae.php.elevated)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func restartPhpFpm(version: String) async {
|
public func restartPhpFpm(version: String) async {
|
||||||
let formula = (version == PhpEnvironments.brewPhpAlias) ? "php" : "php@\(version)"
|
let formula = (version == PhpEnvironments.brewPhpAlias) ? "php" : "php@\(version)"
|
||||||
await brew("services restart \(formula)", sudo: formulae.php.elevated)
|
await brew(container, "services restart \(formula)", sudo: formulae.php.elevated)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func restartNginx() async {
|
public func restartNginx() async {
|
||||||
await brew("services restart \(formulae.nginx)", sudo: formulae.nginx.elevated)
|
await brew(container, "services restart \(formulae.nginx)", sudo: formulae.nginx.elevated)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func restartDnsMasq() async {
|
public func restartDnsMasq() async {
|
||||||
await brew("services restart \(formulae.dnsmasq)", sudo: formulae.dnsmasq.elevated)
|
await brew(container, "services restart \(formulae.dnsmasq)", sudo: formulae.dnsmasq.elevated)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func stopValetServices() async {
|
public func stopValetServices() async {
|
||||||
await brew("services stop \(formulae.php)", sudo: formulae.php.elevated)
|
await brew(container, "services stop \(formulae.php)", sudo: formulae.php.elevated)
|
||||||
await brew("services stop \(formulae.nginx)", sudo: formulae.nginx.elevated)
|
await brew(container, "services stop \(formulae.nginx)", sudo: formulae.nginx.elevated)
|
||||||
await brew("services stop \(formulae.dnsmasq)", sudo: formulae.dnsmasq.elevated)
|
await brew(container, "services stop \(formulae.dnsmasq)", sudo: formulae.dnsmasq.elevated)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fixHomebrewPermissions() throws {
|
public func fixHomebrewPermissions() throws {
|
||||||
@@ -134,8 +134,8 @@ class Actions {
|
|||||||
*/
|
*/
|
||||||
public func fixMyValet() async {
|
public func fixMyValet() async {
|
||||||
await InternalSwitcher().performSwitch(to: PhpEnvironments.brewPhpAlias)
|
await InternalSwitcher().performSwitch(to: PhpEnvironments.brewPhpAlias)
|
||||||
await brew("services restart \(formulae.dnsmasq)", sudo: formulae.dnsmasq.elevated)
|
await brew(container, "services restart \(formulae.dnsmasq)", sudo: formulae.dnsmasq.elevated)
|
||||||
await brew("services restart \(formulae.php)", sudo: formulae.php.elevated)
|
await brew(container, "services restart \(formulae.php)", sudo: formulae.php.elevated)
|
||||||
await brew("services restart \(formulae.nginx)", sudo: formulae.nginx.elevated)
|
await brew(container, "services restart \(formulae.nginx)", sudo: formulae.nginx.elevated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import Foundation
|
|||||||
Runs a `brew` command. Can run as superuser.
|
Runs a `brew` command. Can run as superuser.
|
||||||
*/
|
*/
|
||||||
func brew(
|
func brew(
|
||||||
|
_ container: Container = App.shared.container,
|
||||||
_ command: String,
|
_ command: String,
|
||||||
sudo: Bool = false,
|
sudo: Bool = false,
|
||||||
container: Container = App.shared.container,
|
|
||||||
) async {
|
) async {
|
||||||
await container.shell.quiet("\(sudo ? "sudo " : "")" + "\(container.paths.brew) \(command)")
|
await container.shell.quiet("\(sudo ? "sudo " : "")" + "\(container.paths.brew) \(command)")
|
||||||
}
|
}
|
||||||
@@ -25,12 +25,10 @@ func brew(
|
|||||||
Runs `sed` in order to replace all occurrences of a string in a specific file with another.
|
Runs `sed` in order to replace all occurrences of a string in a specific file with another.
|
||||||
*/
|
*/
|
||||||
func sed(
|
func sed(
|
||||||
|
_ container: Container = App.shared.container,
|
||||||
file: String,
|
file: String,
|
||||||
original: String,
|
original: String,
|
||||||
replacement: String,
|
replacement: String
|
||||||
filesystem: FileSystemProtocol = App.shared.container.filesystem,
|
|
||||||
shell: ShellProtocol = App.shared.container.shell,
|
|
||||||
paths: Paths = App.shared.container.paths,
|
|
||||||
) async {
|
) async {
|
||||||
// Escape slashes (or `sed` won't work)
|
// Escape slashes (or `sed` won't work)
|
||||||
let e_original = original.replacingOccurrences(of: "/", with: "\\/")
|
let e_original = original.replacingOccurrences(of: "/", with: "\\/")
|
||||||
@@ -38,17 +36,21 @@ func sed(
|
|||||||
|
|
||||||
// Check if gsed exists; it is able to follow symlinks,
|
// Check if gsed exists; it is able to follow symlinks,
|
||||||
// which we want to do to toggle the extension
|
// which we want to do to toggle the extension
|
||||||
if filesystem.fileExists("\(paths.binPath)/gsed") {
|
if container.filesystem.fileExists("\(container.paths.binPath)/gsed") {
|
||||||
await shell.quiet("\(paths.binPath)/gsed -i --follow-symlinks 's/\(e_original)/\(e_replacement)/g' \(file)")
|
await container.shell.quiet("\(container.paths.binPath)/gsed -i --follow-symlinks 's/\(e_original)/\(e_replacement)/g' \(file)")
|
||||||
} else {
|
} else {
|
||||||
await shell.quiet("sed -i '' 's/\(e_original)/\(e_replacement)/g' \(file)")
|
await container.shell.quiet("sed -i '' 's/\(e_original)/\(e_replacement)/g' \(file)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Uses `grep` to determine whether a particular query string can be found in a particular file.
|
Uses `grep` to determine whether a particular query string can be found in a particular file.
|
||||||
*/
|
*/
|
||||||
func grepContains(file: String, query: String, shell: ShellProtocol = App.shared.container.shell) async -> Bool {
|
func grepContains(
|
||||||
|
shell: ShellProtocol = App.shared.container.shell,
|
||||||
|
file: String,
|
||||||
|
query: String
|
||||||
|
) async -> Bool {
|
||||||
return await shell.pipe("""
|
return await shell.pipe("""
|
||||||
grep -q '\(query)' \(file); [ $? -eq 0 ] && echo "YES" || echo "NO"
|
grep -q '\(query)' \(file); [ $? -eq 0 ] && echo "YES" || echo "NO"
|
||||||
""").out
|
""").out
|
||||||
|
|||||||
@@ -10,7 +10,12 @@ import Foundation
|
|||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
var replacingTildeWithHomeDirectory: String {
|
var replacingTildeWithHomeDirectory: String {
|
||||||
return self.replacingOccurrences(of: "~", with: App.shared.container.paths.homePath)
|
// Try and check if there's a shared container
|
||||||
|
if let paths = App.shared.container.paths {
|
||||||
|
return self.replacingOccurrences(of: "~", with: paths.homePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,14 +40,14 @@ class ActivePhpInstallation {
|
|||||||
|
|
||||||
// MARK: - Initializer
|
// MARK: - Initializer
|
||||||
|
|
||||||
public static func load() -> ActivePhpInstallation? {
|
public static func load(
|
||||||
let container = App.shared.container
|
container: Container = App.shared.container
|
||||||
|
) -> ActivePhpInstallation? {
|
||||||
if !container.filesystem.fileExists(container.paths.phpConfig) {
|
if !container.filesystem.fileExists(container.paths.phpConfig) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return ActivePhpInstallation()
|
return ActivePhpInstallation(container: container)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(container: Container = App.shared.container) {
|
init(container: Container = App.shared.container) {
|
||||||
@@ -83,7 +83,7 @@ class ActivePhpInstallation {
|
|||||||
|
|
||||||
// See if any extensions are present in said .ini files
|
// See if any extensions are present in said .ini files
|
||||||
paths.forEach { (iniFilePath) in
|
paths.forEach { (iniFilePath) in
|
||||||
if let file = PhpConfigurationFile.from(filePath: iniFilePath) {
|
if let file = PhpConfigurationFile.from(container, filePath: iniFilePath) {
|
||||||
iniFiles.append(file)
|
iniFiles.append(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class PhpEnvironments {
|
|||||||
*/
|
*/
|
||||||
init(container: Container = App.shared.container) {
|
init(container: Container = App.shared.container) {
|
||||||
self.container = container
|
self.container = container
|
||||||
self.currentInstall = ActivePhpInstallation.load()
|
self.currentInstall = ActivePhpInstallation.load(container: container)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -170,7 +170,7 @@ class PhpEnvironments {
|
|||||||
|
|
||||||
// Avoid inserting a duplicate
|
// Avoid inserting a duplicate
|
||||||
if !supportedVersions.contains(phpAlias) && container.filesystem.fileExists("\(container.paths.optPath)/php/bin/php") {
|
if !supportedVersions.contains(phpAlias) && container.filesystem.fileExists("\(container.paths.optPath)/php/bin/php") {
|
||||||
let phpAliasInstall = PhpInstallation(phpAlias)
|
let phpAliasInstall = PhpInstallation(container, phpAlias)
|
||||||
// Before inserting, ensure that the actual output matches the alias
|
// Before inserting, ensure that the actual output matches the alias
|
||||||
// if that isn't the case, our formula remains out-of-date
|
// if that isn't the case, our formula remains out-of-date
|
||||||
if !phpAliasInstall.isMissingBinary {
|
if !phpAliasInstall.isMissingBinary {
|
||||||
@@ -190,7 +190,7 @@ class PhpEnvironments {
|
|||||||
var mappedVersions: [String: PhpInstallation] = [:]
|
var mappedVersions: [String: PhpInstallation] = [:]
|
||||||
|
|
||||||
availablePhpVersions.forEach { version in
|
availablePhpVersions.forEach { version in
|
||||||
mappedVersions[version] = PhpInstallation(version)
|
mappedVersions[version] = PhpInstallation(container, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
cachedPhpInstallations = mappedVersions
|
cachedPhpInstallations = mappedVersions
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class PhpConfigurationFile: CreatedFromFile {
|
class PhpConfigurationFile: CreatedFromFile {
|
||||||
|
var container: Container
|
||||||
|
|
||||||
struct ConfigValue {
|
struct ConfigValue {
|
||||||
let lineIndex: Int
|
let lineIndex: Int
|
||||||
@@ -32,24 +33,25 @@ class PhpConfigurationFile: CreatedFromFile {
|
|||||||
|
|
||||||
/** Resolves a PHP configuration file (.ini) */
|
/** Resolves a PHP configuration file (.ini) */
|
||||||
static func from(
|
static func from(
|
||||||
filePath: String,
|
_ container: Container,
|
||||||
container: Container = App.shared.container
|
filePath: String
|
||||||
) -> Self? {
|
) -> Self? {
|
||||||
let path = filePath.replacingOccurrences(of: "~", with: container.paths.homePath)
|
let path = filePath.replacingOccurrences(of: "~", with: container.paths.homePath)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let fileContents = try App.shared.container.filesystem.getStringFromFile(path)
|
let fileContents = try container.filesystem.getStringFromFile(path)
|
||||||
return Self.init(path: path, contents: fileContents)
|
return Self.init(container, path: path, contents: fileContents)
|
||||||
} catch {
|
} catch {
|
||||||
Log.warn("Could not read the PHP configuration file at: `\(filePath)`")
|
Log.warn("Could not read the PHP configuration file at: `\(filePath)`")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init(path: String, contents: String) {
|
required init(_ container: Container, path: String, contents: String) {
|
||||||
|
self.container = container
|
||||||
self.filePath = path
|
self.filePath = path
|
||||||
self.lines = contents.components(separatedBy: "\n")
|
self.lines = contents.components(separatedBy: "\n")
|
||||||
self.extensions = PhpExtension.from(lines, filePath: path)
|
self.extensions = PhpExtension.from(container, lines, filePath: path)
|
||||||
self.content = Self.parseConfig(lines: lines)
|
self.content = Self.parseConfig(lines: lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +118,7 @@ class PhpConfigurationFile: CreatedFromFile {
|
|||||||
public func reload() {
|
public func reload() {
|
||||||
self.lines = try! String(contentsOfFile: self.filePath)
|
self.lines = try! String(contentsOfFile: self.filePath)
|
||||||
.components(separatedBy: "\n")
|
.components(separatedBy: "\n")
|
||||||
self.extensions = PhpExtension.from(lines, filePath: self.filePath)
|
self.extensions = PhpExtension.from(container, lines, filePath: self.filePath)
|
||||||
self.content = Self.parseConfig(lines: lines)
|
self.content = Self.parseConfig(lines: lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
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.
|
||||||
@@ -15,8 +16,8 @@ import Foundation
|
|||||||
- 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 {
|
||||||
|
|
||||||
/// The file where this extension was located.
|
/// The file where this extension was located.
|
||||||
var file: String
|
var file: String
|
||||||
|
|
||||||
@@ -54,7 +55,9 @@ class PhpExtension {
|
|||||||
/**
|
/**
|
||||||
When registering an extension, we do that based on the line found inside the .ini file.
|
When registering an extension, we do that based on the line found inside the .ini file.
|
||||||
*/
|
*/
|
||||||
init(_ line: String, file: String) {
|
init(_ container: Container, _ line: String, file: String) {
|
||||||
|
self.container = container
|
||||||
|
|
||||||
let regex = try! NSRegularExpression(pattern: Self.extensionRegex, options: [])
|
let regex = try! NSRegularExpression(pattern: Self.extensionRegex, options: [])
|
||||||
let match = regex.matches(in: line, options: [], range: NSRange(location: 0, length: line.count)).first
|
let match = regex.matches(in: line, options: [], range: NSRange(location: 0, length: line.count)).first
|
||||||
let range = Range(match!.range(withName: "name"), in: line)!
|
let range = Range(match!.range(withName: "name"), in: line)!
|
||||||
@@ -82,7 +85,7 @@ class PhpExtension {
|
|||||||
// ENABLED: Line where the comment delimiter (;) is removed
|
// ENABLED: Line where the comment delimiter (;) is removed
|
||||||
: line.replacingOccurrences(of: "; ", with: "")
|
: line.replacingOccurrences(of: "; ", with: "")
|
||||||
|
|
||||||
await sed(file: file, original: line, replacement: newLine)
|
await sed(container, file: file, original: line, replacement: newLine)
|
||||||
|
|
||||||
self.enabled = !newLine.starts(with: ";")
|
self.enabled = !newLine.starts(with: ";")
|
||||||
self.line = newLine
|
self.line = newLine
|
||||||
@@ -96,15 +99,15 @@ class PhpExtension {
|
|||||||
|
|
||||||
// MARK: - Static Methods
|
// MARK: - Static Methods
|
||||||
|
|
||||||
static func from(_ lines: [String], filePath: String) -> [PhpExtension] {
|
static func from(_ container: Container, _ lines: [String], filePath: String) -> [PhpExtension] {
|
||||||
return lines.filter {
|
return lines.filter {
|
||||||
return $0.range(of: Self.extensionRegex, options: .regularExpression) != nil
|
return $0.range(of: Self.extensionRegex, options: .regularExpression) != nil
|
||||||
}.map {
|
}.map {
|
||||||
return PhpExtension($0, file: filePath)
|
return PhpExtension(container, $0, file: filePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func from(filePath: String) -> [PhpExtension] {
|
static func from(_ container: Container, filePath: String) -> [PhpExtension] {
|
||||||
let file = try? String(contentsOfFile: filePath)
|
let file = try? String(contentsOfFile: filePath)
|
||||||
|
|
||||||
if file == nil {
|
if file == nil {
|
||||||
@@ -113,6 +116,7 @@ class PhpExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Self.from(
|
return Self.from(
|
||||||
|
container,
|
||||||
file!.components(separatedBy: "\n"),
|
file!.components(separatedBy: "\n"),
|
||||||
filePath: filePath
|
filePath: filePath
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import ContainerMacro
|
|||||||
|
|
||||||
@ContainerAccess
|
@ContainerAccess
|
||||||
class PhpInstallation {
|
class PhpInstallation {
|
||||||
|
|
||||||
var versionNumber: VersionNumber
|
var versionNumber: VersionNumber
|
||||||
|
|
||||||
var iniFiles: [PhpConfigurationFile] = []
|
var iniFiles: [PhpConfigurationFile] = []
|
||||||
@@ -40,7 +39,7 @@ class PhpInstallation {
|
|||||||
In order to determine details about a PHP installation,
|
In order to determine details about a PHP installation,
|
||||||
we’ll simply run `php-config --version` in the relevant directory.
|
we’ll simply run `php-config --version` in the relevant directory.
|
||||||
*/
|
*/
|
||||||
init(container: Container = App.shared.container, _ version: String) {
|
init(_ container: Container, _ version: String) {
|
||||||
self.container = container
|
self.container = container
|
||||||
|
|
||||||
let phpConfigExecutablePath = "\(container.paths.optPath)/php@\(version)/bin/php-config",
|
let phpConfigExecutablePath = "\(container.paths.optPath)/php@\(version)/bin/php-config",
|
||||||
@@ -105,7 +104,7 @@ class PhpInstallation {
|
|||||||
|
|
||||||
// See if any extensions are present in said .ini files
|
// See if any extensions are present in said .ini files
|
||||||
paths.forEach { (iniFilePath) in
|
paths.forEach { (iniFilePath) in
|
||||||
if let file = PhpConfigurationFile.from(filePath: iniFilePath) {
|
if let file = PhpConfigurationFile.from(container, filePath: iniFilePath) {
|
||||||
iniFiles.append(file)
|
iniFiles.append(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class InternalSwitcher: PhpSwitcher {
|
|||||||
|
|
||||||
if Valet.installed {
|
if Valet.installed {
|
||||||
Log.info("Restarting nginx, just to be sure!")
|
Log.info("Restarting nginx, just to be sure!")
|
||||||
await brew("services restart nginx", sudo: true)
|
await brew(container, "services restart nginx", sudo: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info("The new version(s) have been linked!")
|
Log.info("The new version(s) have been linked!")
|
||||||
@@ -78,10 +78,10 @@ class InternalSwitcher: PhpSwitcher {
|
|||||||
|
|
||||||
func unlinkAndStopPhpVersion(_ version: String) async {
|
func unlinkAndStopPhpVersion(_ version: String) async {
|
||||||
let formula = (version == PhpEnvironments.brewPhpAlias) ? "php" : "php@\(version)"
|
let formula = (version == PhpEnvironments.brewPhpAlias) ? "php" : "php@\(version)"
|
||||||
await brew("unlink \(formula)")
|
await brew(container, "unlink \(formula)")
|
||||||
|
|
||||||
if Valet.installed {
|
if Valet.installed {
|
||||||
await brew("services stop \(formula)", sudo: true)
|
await brew(container, "services stop \(formula)", sudo: true)
|
||||||
Log.info("Unlinked and stopped services for \(formula)")
|
Log.info("Unlinked and stopped services for \(formula)")
|
||||||
} else {
|
} else {
|
||||||
Log.info("Unlinked \(formula)")
|
Log.info("Unlinked \(formula)")
|
||||||
@@ -93,13 +93,13 @@ class InternalSwitcher: PhpSwitcher {
|
|||||||
|
|
||||||
if primary {
|
if primary {
|
||||||
Log.info("\(formula) is the primary formula, linking...")
|
Log.info("\(formula) is the primary formula, linking...")
|
||||||
await brew("link \(formula) --overwrite --force")
|
await brew(container, "link \(formula) --overwrite --force")
|
||||||
} else {
|
} else {
|
||||||
Log.info("\(formula) is an isolated PHP version, not linking!")
|
Log.info("\(formula) is an isolated PHP version, not linking!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if Valet.installed {
|
if Valet.installed {
|
||||||
await brew("services start \(formula)", sudo: true)
|
await brew(container, "services start \(formula)", sudo: true)
|
||||||
|
|
||||||
if Valet.enabled(feature: .isolatedSites) && primary {
|
if Valet.enabled(feature: .isolatedSites) && primary {
|
||||||
let socketVersion = version.replacingOccurrences(of: ".", with: "")
|
let socketVersion = version.replacingOccurrences(of: ".", with: "")
|
||||||
|
|||||||
@@ -9,7 +9,5 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol CreatedFromFile {
|
protocol CreatedFromFile {
|
||||||
|
static func from(_ container: Container, filePath: String) -> Self?
|
||||||
static func from(filePath: String, container: Container) -> Self?
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
34
phpmon/Container+Fake.swift
Normal file
34
phpmon/Container+Fake.swift
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// Container+Fake.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 16/10/2025.
|
||||||
|
// Copyright © 2025 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
extension Container {
|
||||||
|
public func overrideFake(
|
||||||
|
shellExpectations: [String: BatchFakeShellOutput] = [:],
|
||||||
|
fileSystemFiles: [String: FakeFile] = [:],
|
||||||
|
commands: [String: String] = [:]
|
||||||
|
) {
|
||||||
|
self.shell = TestableShell(expectations: shellExpectations)
|
||||||
|
self.filesystem = TestableFileSystem(files: fileSystemFiles)
|
||||||
|
self.command = TestableCommand(commands: commands)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func fake(
|
||||||
|
shell: [String: BatchFakeShellOutput] = [:],
|
||||||
|
files: [String: FakeFile] = [:],
|
||||||
|
commands: [String: String] = [:]
|
||||||
|
) -> Container {
|
||||||
|
let container = Container()
|
||||||
|
container.prepare()
|
||||||
|
container.overrideFake(
|
||||||
|
shellExpectations: shell,
|
||||||
|
fileSystemFiles: files,
|
||||||
|
commands: commands
|
||||||
|
)
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,9 +37,9 @@ class Container {
|
|||||||
self.command = TestableCommand(commands: config.commandOutput)
|
self.command = TestableCommand(commands: config.commandOutput)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func overrideFake() {
|
public static func real() -> Container {
|
||||||
self.shell = TestableShell(expectations: [:])
|
let container = Container()
|
||||||
self.filesystem = TestableFileSystem(files: [:])
|
container.prepare()
|
||||||
self.command = TestableCommand(commands: [:])
|
return container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class App {
|
|||||||
The dependency container.
|
The dependency container.
|
||||||
This is supposed to be injected, so direct access is discouraged.
|
This is supposed to be injected, so direct access is discouraged.
|
||||||
*/
|
*/
|
||||||
let container = Container()
|
var container: Container = Container()
|
||||||
|
|
||||||
/** The list of preferences that are currently active. */
|
/** The list of preferences that are currently active. */
|
||||||
var preferences: [PreferenceName: Bool]!
|
var preferences: [PreferenceName: Bool]!
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class AppUpdater {
|
|||||||
|
|
||||||
let caskUrl = Constants.Urls.UpdateCheckEndpoint
|
let caskUrl = Constants.Urls.UpdateCheckEndpoint
|
||||||
|
|
||||||
guard let caskFile = await CaskFile.from(url: caskUrl) else {
|
guard let caskFile = await CaskFile.from(App.shared.container, url: caskUrl) else {
|
||||||
Log.err("The contents of the CaskFile at '\(caskUrl.absoluteString)' could not be retrieved.")
|
Log.err("The contents of the CaskFile at '\(caskUrl.absoluteString)' could not be retrieved.")
|
||||||
presentCouldNotRetrieveUpdateIfInteractive()
|
presentCouldNotRetrieveUpdateIfInteractive()
|
||||||
return .networkError
|
return .networkError
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ class ValetServicesManager: ServicesManager {
|
|||||||
|
|
||||||
// Run the command
|
// Run the command
|
||||||
await brew(
|
await brew(
|
||||||
|
container,
|
||||||
"services \(action) \(wrapper.formula.name)",
|
"services \(action) \(wrapper.formula.name)",
|
||||||
sudo: wrapper.formula.elevated
|
sudo: wrapper.formula.elevated
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -30,16 +30,18 @@ struct BrewPhpExtension: Hashable, Comparable {
|
|||||||
return "\(name)@\(phpVersion)"
|
return "\(name)@\(phpVersion)"
|
||||||
}
|
}
|
||||||
|
|
||||||
init(path: String, name: String, phpVersion: String) {
|
init(_ container: Container, path: String, name: String, phpVersion: String) {
|
||||||
self.path = path
|
self.path = path
|
||||||
self.name = name
|
self.name = name
|
||||||
self.phpVersion = phpVersion
|
self.phpVersion = phpVersion
|
||||||
|
|
||||||
self.isInstalled = BrewPhpExtension.hasInstallationReceipt(
|
self.isInstalled = BrewPhpExtension.hasInstallationReceipt(
|
||||||
for: "\(name)@\(phpVersion)"
|
container, for: "\(name)@\(phpVersion)"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.dependencies = BrewPhpExtension.extractDependencies(from: path)
|
self.dependencies = BrewPhpExtension.extractDependencies(
|
||||||
|
container, from: path
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasAlternativeInstall: Bool {
|
var hasAlternativeInstall: Bool {
|
||||||
@@ -58,8 +60,8 @@ struct BrewPhpExtension: Hashable, Comparable {
|
|||||||
.first { $0.dependencies.contains("shivammathur/extensions/\(self.formulaName)") }
|
.first { $0.dependencies.contains("shivammathur/extensions/\(self.formulaName)") }
|
||||||
}
|
}
|
||||||
|
|
||||||
static func hasInstallationReceipt(for formulaName: String) -> Bool {
|
static func hasInstallationReceipt(_ container: Container, for formulaName: String) -> Bool {
|
||||||
return App.shared.container.filesystem.fileExists("\(App.shared.container.paths.optPath)/\(formulaName)/INSTALL_RECEIPT.json")
|
return container.filesystem.fileExists("\(container.paths.optPath)/\(formulaName)/INSTALL_RECEIPT.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
static func < (lhs: BrewPhpExtension, rhs: BrewPhpExtension) -> Bool {
|
static func < (lhs: BrewPhpExtension, rhs: BrewPhpExtension) -> Bool {
|
||||||
@@ -70,11 +72,11 @@ struct BrewPhpExtension: Hashable, Comparable {
|
|||||||
return lhs.name == rhs.name
|
return lhs.name == rhs.name
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func extractDependencies(from path: String) -> [String] {
|
private static func extractDependencies(_ container: Container, from path: String) -> [String] {
|
||||||
let regexPattern = #"depends_on "(.*)""#
|
let regexPattern = #"depends_on "(.*)""#
|
||||||
var dependencies: [String] = []
|
var dependencies: [String] = []
|
||||||
|
|
||||||
guard let content = try? App.shared.container.filesystem.getStringFromFile(path) else {
|
guard let content = try? container.filesystem.getStringFromFile(path) else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,8 @@ import Foundation
|
|||||||
import ContainerMacro
|
import ContainerMacro
|
||||||
|
|
||||||
struct BrewPhpFormula: Equatable {
|
struct BrewPhpFormula: Equatable {
|
||||||
var container: Container {
|
/// The dependency container.
|
||||||
return App.shared.container
|
let container: Container
|
||||||
}
|
|
||||||
|
|
||||||
/// Name of the formula.
|
/// Name of the formula.
|
||||||
let name: String
|
let name: String
|
||||||
@@ -38,12 +37,14 @@ struct BrewPhpFormula: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(
|
init(
|
||||||
|
_ container: Container,
|
||||||
name: String,
|
name: String,
|
||||||
displayName: String,
|
displayName: String,
|
||||||
installedVersion: String?,
|
installedVersion: String?,
|
||||||
upgradeVersion: String?,
|
upgradeVersion: String?,
|
||||||
prerelease: Bool = false
|
prerelease: Bool = false
|
||||||
) {
|
) {
|
||||||
|
self.container = container
|
||||||
self.name = name
|
self.name = name
|
||||||
self.displayName = displayName
|
self.displayName = displayName
|
||||||
self.installedVersion = installedVersion
|
self.installedVersion = installedVersion
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class BrewPhpFormulaeHandler: HandlesBrewPhpFormulae {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return BrewPhpFormula(
|
return BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: formula,
|
name: formula,
|
||||||
displayName: "PHP \(version)",
|
displayName: "PHP \(version)",
|
||||||
installedVersion: fullVersion,
|
installedVersion: fullVersion,
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class BrewTapFormulae {
|
class BrewTapFormulae {
|
||||||
public static func from(tap: String) -> [String: [BrewPhpExtension]] {
|
public static func from(_ container: Container, tap: String) -> [String: [BrewPhpExtension]] {
|
||||||
let directory = "\(App.shared.container.paths.tapPath)/\(tap)/Formula"
|
let directory = "\(container.paths.tapPath)/\(tap)/Formula"
|
||||||
|
|
||||||
let files = try? App.shared.container.filesystem.getShallowContentsOfDirectory(directory)
|
let files = try? container.filesystem.getShallowContentsOfDirectory(directory)
|
||||||
|
|
||||||
var availableExtensions = [String: [BrewPhpExtension]]()
|
var availableExtensions = [String: [BrewPhpExtension]]()
|
||||||
|
|
||||||
@@ -35,7 +35,8 @@ class BrewTapFormulae {
|
|||||||
|
|
||||||
// Create a new BrewPhpExtension object (determines if installed)
|
// Create a new BrewPhpExtension object (determines if installed)
|
||||||
let phpExtension = BrewPhpExtension(
|
let phpExtension = BrewPhpExtension(
|
||||||
path: "\(App.shared.container.paths.tapPath)/\(tap)/Formula/\(file)",
|
container,
|
||||||
|
path: "\(container.paths.tapPath)/\(tap)/Formula/\(file)",
|
||||||
name: phpExtensionName,
|
name: phpExtensionName,
|
||||||
phpVersion: phpVersion
|
phpVersion: phpVersion
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ struct CaskFile {
|
|||||||
return self.properties["version"]!
|
return self.properties["version"]!
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func loadFromApi(_ url: URL) async -> String {
|
private static func loadFromApi(_ container: Container, _ url: URL) async -> String {
|
||||||
if App.hasLoadedTestableConfiguration || url.absoluteString.contains("https://raw.githubusercontent.com") {
|
if isRunningTests || App.hasLoadedTestableConfiguration || url.absoluteString.contains("https://raw.githubusercontent.com") {
|
||||||
return await App.shared.container.shell.pipe("curl -s --max-time 10 '\(url.absoluteString)'").out
|
return await container.shell.pipe("curl -s --max-time 10 '\(url.absoluteString)'").out
|
||||||
} else {
|
} else {
|
||||||
return await App.shared.container.shell.pipe("""
|
return await container.shell.pipe("""
|
||||||
curl -s --max-time 10 \
|
curl -s --max-time 10 \
|
||||||
-H "User-Agent: phpmon-curl/1.0" \
|
-H "User-Agent: phpmon-curl/1.0" \
|
||||||
-H "X-phpmon-version: \(App.shortVersion) (\(App.bundleVersion))" \
|
-H "X-phpmon-version: \(App.shortVersion) (\(App.bundleVersion))" \
|
||||||
@@ -39,13 +39,13 @@ struct CaskFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func from(url: URL) async -> CaskFile? {
|
public static func from(_ container: Container, url: URL) async -> CaskFile? {
|
||||||
var string: String?
|
var string: String?
|
||||||
|
|
||||||
if url.scheme == "file" {
|
if url.scheme == "file" {
|
||||||
string = try? String(contentsOf: url)
|
string = try? String(contentsOf: url)
|
||||||
} else {
|
} else {
|
||||||
string = await CaskFile.loadFromApi(url)
|
string = await CaskFile.loadFromApi(container, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let string else {
|
guard let string else {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class NginxConfigurationFile: CreatedFromFile {
|
class NginxConfigurationFile: CreatedFromFile {
|
||||||
|
|
||||||
/// Contents of the Nginx file in question, as a string.
|
/// Contents of the Nginx file in question, as a string.
|
||||||
var contents: String!
|
var contents: String!
|
||||||
|
|
||||||
@@ -21,8 +20,8 @@ class NginxConfigurationFile: CreatedFromFile {
|
|||||||
|
|
||||||
/** Resolves an nginx configuration file (.conf) */
|
/** Resolves an nginx configuration file (.conf) */
|
||||||
static func from(
|
static func from(
|
||||||
|
_ container: Container,
|
||||||
filePath: String,
|
filePath: String,
|
||||||
container: Container = App.shared.container
|
|
||||||
) -> Self? {
|
) -> Self? {
|
||||||
let path = filePath.replacingOccurrences(of: "~", with: container.paths.homePath)
|
let path = filePath.replacingOccurrences(of: "~", with: container.paths.homePath)
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class ValetDomainScanner: DomainScanner {
|
|||||||
private func isSite(_ entry: String, forPath path: String) -> Bool {
|
private func isSite(_ entry: String, forPath path: String) -> Bool {
|
||||||
let siteDir = path + "/" + entry
|
let siteDir = path + "/" + entry
|
||||||
|
|
||||||
return (App.shared.container.filesystem.isDirectory(siteDir) || App.shared.container.filesystem.isSymlink(siteDir))
|
return (container.filesystem.isDirectory(siteDir) || container.filesystem.isSymlink(siteDir))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Proxies
|
// MARK: - Proxies
|
||||||
@@ -100,7 +100,7 @@ class ValetDomainScanner: DomainScanner {
|
|||||||
return !$0.starts(with: ".")
|
return !$0.starts(with: ".")
|
||||||
}
|
}
|
||||||
.compactMap {
|
.compactMap {
|
||||||
return NginxConfigurationFile.from(filePath: "\(directoryPath)/\($0)")
|
return NginxConfigurationFile.from(container, filePath: "\(directoryPath)/\($0)")
|
||||||
}
|
}
|
||||||
.filter {
|
.filter {
|
||||||
return $0.proxy != nil
|
return $0.proxy != nil
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class FakeValetSite: ValetSite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let isolated = isolated {
|
if let isolated = isolated {
|
||||||
self.isolatedPhpVersion = PhpInstallation(isolated)
|
self.isolatedPhpVersion = PhpInstallation(container, isolated)
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.phpEnvs.currentInstall != nil {
|
if container.phpEnvs.currentInstall != nil {
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ class ValetSite: ValetListable {
|
|||||||
) -> String? {
|
) -> String? {
|
||||||
if container.filesystem.fileExists(filePath) {
|
if container.filesystem.fileExists(filePath) {
|
||||||
return NginxConfigurationFile
|
return NginxConfigurationFile
|
||||||
.from(filePath: filePath)?
|
.from(container, filePath: filePath)?
|
||||||
.isolatedVersion ?? nil
|
.isolatedVersion ?? nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class BytePhpPreference: PhpPreference {
|
|||||||
didSet { updatedFieldValue() }
|
didSet { updatedFieldValue() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override init(container: Container = App.shared.container, key: String) {
|
override init(_ container: Container = App.shared.container, key: String) {
|
||||||
let value = container.command.execute(
|
let value = container.command.execute(
|
||||||
path: container.paths.php, arguments: ["-r", "echo ini_get('\(key)');"],
|
path: container.paths.php, arguments: ["-r", "echo ini_get('\(key)');"],
|
||||||
trimNewlines: false
|
trimNewlines: false
|
||||||
@@ -48,7 +48,7 @@ class BytePhpPreference: PhpPreference {
|
|||||||
self.value = value
|
self.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
super.init(container: container, key: key)
|
super.init(container, key: key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Save Value
|
// MARK: Save Value
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import ContainerMacro
|
|||||||
class PhpPreference {
|
class PhpPreference {
|
||||||
let key: String
|
let key: String
|
||||||
|
|
||||||
init(container: Container = App.shared.container, key: String) {
|
init(_ container: Container = App.shared.container, key: String) {
|
||||||
self.container = container
|
self.container = container
|
||||||
self.key = key
|
self.key = key
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ extension WarningManager {
|
|||||||
return [
|
return [
|
||||||
Warning(
|
Warning(
|
||||||
command: {
|
command: {
|
||||||
return await App.shared.container.shell.pipe("sysctl -n sysctl.proc_translated").out
|
return await self.container.shell.pipe("sysctl -n sysctl.proc_translated").out
|
||||||
.trimmingCharacters(in: .whitespacesAndNewlines) == "1"
|
.trimmingCharacters(in: .whitespacesAndNewlines) == "1"
|
||||||
},
|
},
|
||||||
name: "Running PHP Monitor with Rosetta on Apple Silicon",
|
name: "Running PHP Monitor with Rosetta on Apple Silicon",
|
||||||
@@ -23,8 +23,8 @@ extension WarningManager {
|
|||||||
),
|
),
|
||||||
Warning(
|
Warning(
|
||||||
command: {
|
command: {
|
||||||
return !App.shared.container.shell.PATH.contains("\(App.shared.container.paths.homePath)/.config/phpmon/bin") &&
|
return !self.container.shell.PATH.contains("\(self.container.paths.homePath)/.config/phpmon/bin") &&
|
||||||
!App.shared.container.filesystem.isWriteableFile("/usr/local/bin/")
|
!self.container.filesystem.isWriteableFile("/usr/local/bin/")
|
||||||
},
|
},
|
||||||
name: "Helpers cannot be symlinked and not in PATH",
|
name: "Helpers cannot be symlinked and not in PATH",
|
||||||
title: "warnings.helper_permissions.title",
|
title: "warnings.helper_permissions.title",
|
||||||
@@ -34,7 +34,7 @@ extension WarningManager {
|
|||||||
"warnings.helper_permissions.symlink"
|
"warnings.helper_permissions.symlink"
|
||||||
] },
|
] },
|
||||||
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries",
|
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries",
|
||||||
fix: App.shared.container.paths.shell == "/bin/zsh" ? {
|
fix: self.container.paths.shell == "/bin/zsh" ? {
|
||||||
// Add to PATH
|
// Add to PATH
|
||||||
await ZshRunCommand().addPhpMonitorPath()
|
await ZshRunCommand().addPhpMonitorPath()
|
||||||
// Finally, perform environment checks again
|
// Finally, perform environment checks again
|
||||||
@@ -43,7 +43,7 @@ extension WarningManager {
|
|||||||
),
|
),
|
||||||
Warning(
|
Warning(
|
||||||
command: {
|
command: {
|
||||||
App.shared.container.phpEnvs.currentInstall?.extensions.contains { $0.name == "xdebug" } ?? false
|
self.container.phpEnvs.currentInstall?.extensions.contains { $0.name == "xdebug" } ?? false
|
||||||
&& !Xdebug().enabled
|
&& !Xdebug().enabled
|
||||||
},
|
},
|
||||||
name: "Missing configuration file for `xdebug.mode`",
|
name: "Missing configuration file for `xdebug.mode`",
|
||||||
@@ -53,17 +53,17 @@ extension WarningManager {
|
|||||||
] },
|
] },
|
||||||
url: "https://xdebug.org/docs/install#mode",
|
url: "https://xdebug.org/docs/install#mode",
|
||||||
fix: {
|
fix: {
|
||||||
if let php = App.shared.container.phpEnvs.currentInstall {
|
if let php = self.container.phpEnvs.currentInstall {
|
||||||
if let xdebug = php.extensions.first(where: { $0.name == "xdebug" }),
|
if let xdebug = php.extensions.first(where: { $0.name == "xdebug" }),
|
||||||
let original = try? App.shared.container.filesystem.getStringFromFile(xdebug.file) {
|
let original = try? self.container.filesystem.getStringFromFile(xdebug.file) {
|
||||||
// Append xdebug.mode = off to the file
|
// Append xdebug.mode = off to the file
|
||||||
try? App.shared.container.filesystem.writeAtomicallyToFile(
|
try? self.container.filesystem.writeAtomicallyToFile(
|
||||||
xdebug.file,
|
xdebug.file,
|
||||||
content: original + "\nxdebug.mode = off"
|
content: original + "\nxdebug.mode = off"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reload extension configuration by updating PHP installation info (reload)
|
// Reload extension configuration by updating PHP installation info (reload)
|
||||||
App.shared.container.phpEnvs.currentInstall = ActivePhpInstallation()
|
self.container.phpEnvs.currentInstall = ActivePhpInstallation()
|
||||||
|
|
||||||
// Finally, reload warnings
|
// Finally, reload warnings
|
||||||
await self.checkEnvironment()
|
await self.checkEnvironment()
|
||||||
@@ -82,7 +82,7 @@ extension WarningManager {
|
|||||||
] },
|
] },
|
||||||
url: "https://github.com/shivammathur/homebrew-php",
|
url: "https://github.com/shivammathur/homebrew-php",
|
||||||
fix: {
|
fix: {
|
||||||
await App.shared.container.shell.quiet("brew tap shivammathur/php")
|
await self.container.shell.quiet("brew tap shivammathur/php")
|
||||||
await BrewDiagnostics.shared.loadInstalledTaps()
|
await BrewDiagnostics.shared.loadInstalledTaps()
|
||||||
await self.checkEnvironment()
|
await self.checkEnvironment()
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ extension WarningManager {
|
|||||||
] },
|
] },
|
||||||
url: "https://github.com/shivammathur/homebrew-extensions",
|
url: "https://github.com/shivammathur/homebrew-extensions",
|
||||||
fix: {
|
fix: {
|
||||||
await App.shared.container.shell.quiet("brew tap shivammathur/extensions")
|
await self.container.shell.quiet("brew tap shivammathur/extensions")
|
||||||
await BrewDiagnostics.shared.loadInstalledTaps()
|
await BrewDiagnostics.shared.loadInstalledTaps()
|
||||||
await self.checkEnvironment()
|
await self.checkEnvironment()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ class BrewExtensionsObservable: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func loadExtensionData(for version: String) {
|
public func loadExtensionData(for version: String) {
|
||||||
let tapFormulae = BrewTapFormulae.from(tap: "shivammathur/homebrew-extensions")
|
let tapFormulae = BrewTapFormulae.from(
|
||||||
|
App.shared.container,
|
||||||
|
tap: "shivammathur/homebrew-extensions"
|
||||||
|
)
|
||||||
|
|
||||||
if let filteredTapFormulae = tapFormulae[version] {
|
if let filteredTapFormulae = tapFormulae[version] {
|
||||||
self.extensions = filteredTapFormulae
|
self.extensions = filteredTapFormulae
|
||||||
|
|||||||
@@ -11,8 +11,11 @@ import Foundation
|
|||||||
// swiftlint:disable function_body_length
|
// swiftlint:disable function_body_length
|
||||||
class FakeBrewFormulaeHandler: HandlesBrewPhpFormulae {
|
class FakeBrewFormulaeHandler: HandlesBrewPhpFormulae {
|
||||||
public func loadPhpVersions(loadOutdated: Bool) async -> [BrewPhpFormula] {
|
public func loadPhpVersions(loadOutdated: Bool) async -> [BrewPhpFormula] {
|
||||||
|
let container = App.shared.container
|
||||||
|
|
||||||
return [
|
return [
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php@9.9",
|
name: "php@9.9",
|
||||||
displayName: "PHP 9.9",
|
displayName: "PHP 9.9",
|
||||||
installedVersion: nil,
|
installedVersion: nil,
|
||||||
@@ -20,6 +23,7 @@ class FakeBrewFormulaeHandler: HandlesBrewPhpFormulae {
|
|||||||
prerelease: true
|
prerelease: true
|
||||||
),
|
),
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php@8.4",
|
name: "php@8.4",
|
||||||
displayName: "PHP 8.4",
|
displayName: "PHP 8.4",
|
||||||
installedVersion: nil,
|
installedVersion: nil,
|
||||||
@@ -27,6 +31,7 @@ class FakeBrewFormulaeHandler: HandlesBrewPhpFormulae {
|
|||||||
prerelease: true
|
prerelease: true
|
||||||
),
|
),
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php",
|
name: "php",
|
||||||
displayName: "PHP 8.3",
|
displayName: "PHP 8.3",
|
||||||
installedVersion: nil,
|
installedVersion: nil,
|
||||||
@@ -34,42 +39,49 @@ class FakeBrewFormulaeHandler: HandlesBrewPhpFormulae {
|
|||||||
prerelease: true
|
prerelease: true
|
||||||
),
|
),
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php@8.2",
|
name: "php@8.2",
|
||||||
displayName: "PHP 8.2",
|
displayName: "PHP 8.2",
|
||||||
installedVersion: "8.2.3",
|
installedVersion: "8.2.3",
|
||||||
upgradeVersion: "8.2.4"
|
upgradeVersion: "8.2.4"
|
||||||
),
|
),
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php@8.1",
|
name: "php@8.1",
|
||||||
displayName: "PHP 8.1",
|
displayName: "PHP 8.1",
|
||||||
installedVersion: "8.1.17",
|
installedVersion: "8.1.17",
|
||||||
upgradeVersion: nil
|
upgradeVersion: nil
|
||||||
),
|
),
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php@8.0",
|
name: "php@8.0",
|
||||||
displayName: "PHP 8.0",
|
displayName: "PHP 8.0",
|
||||||
installedVersion: nil,
|
installedVersion: nil,
|
||||||
upgradeVersion: nil
|
upgradeVersion: nil
|
||||||
),
|
),
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php@7.4",
|
name: "php@7.4",
|
||||||
displayName: "PHP 7.4",
|
displayName: "PHP 7.4",
|
||||||
installedVersion: nil,
|
installedVersion: nil,
|
||||||
upgradeVersion: nil
|
upgradeVersion: nil
|
||||||
),
|
),
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php@7.3",
|
name: "php@7.3",
|
||||||
displayName: "PHP 7.3",
|
displayName: "PHP 7.3",
|
||||||
installedVersion: nil,
|
installedVersion: nil,
|
||||||
upgradeVersion: nil
|
upgradeVersion: nil
|
||||||
),
|
),
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php@7.2",
|
name: "php@7.2",
|
||||||
displayName: "PHP 7.2",
|
displayName: "PHP 7.2",
|
||||||
installedVersion: nil,
|
installedVersion: nil,
|
||||||
upgradeVersion: nil
|
upgradeVersion: nil
|
||||||
),
|
),
|
||||||
BrewPhpFormula(
|
BrewPhpFormula(
|
||||||
|
container,
|
||||||
name: "php@7.1",
|
name: "php@7.1",
|
||||||
displayName: "PHP 7.1",
|
displayName: "PHP 7.1",
|
||||||
installedVersion: nil,
|
installedVersion: nil,
|
||||||
|
|||||||
25
tests/PHP Monitor.xctestplan
Normal file
25
tests/PHP Monitor.xctestplan
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"configurations" : [
|
||||||
|
{
|
||||||
|
"id" : "CDAF5C24-6A14-4AD7-B204-61734226DBF0",
|
||||||
|
"name" : "Configuration 1",
|
||||||
|
"options" : {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"defaultOptions" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"testTargets" : [
|
||||||
|
{
|
||||||
|
"parallelizable" : false,
|
||||||
|
"target" : {
|
||||||
|
"containerPath" : "container:PHP Monitor.xcodeproj",
|
||||||
|
"identifier" : "C4F7807825D7F84B000DBC97",
|
||||||
|
"name" : "Unit Tests"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
@@ -9,13 +9,11 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
class FeatureTestCase: XCTestCase {
|
class FeatureTestCase: XCTestCase {
|
||||||
// TODO: make fake filesystem accessible via test case
|
|
||||||
|
|
||||||
public func assertFileSystemHas(
|
public func assertFileSystemHas(
|
||||||
_ path: String,
|
_ path: String,
|
||||||
file: StaticString = #filePath,
|
file: StaticString = #filePath,
|
||||||
line: UInt = #line,
|
line: UInt = #line,
|
||||||
fs: TestableFileSystem
|
in fs: TestableFileSystem
|
||||||
) {
|
) {
|
||||||
XCTAssertTrue(fs.files.keys.contains(path), file: file, line: line)
|
XCTAssertTrue(fs.files.keys.contains(path), file: file, line: line)
|
||||||
}
|
}
|
||||||
@@ -24,7 +22,7 @@ class FeatureTestCase: XCTestCase {
|
|||||||
_ path: String,
|
_ path: String,
|
||||||
file: StaticString = #filePath,
|
file: StaticString = #filePath,
|
||||||
line: UInt = #line,
|
line: UInt = #line,
|
||||||
fs: TestableFileSystem
|
in fs: TestableFileSystem
|
||||||
) {
|
) {
|
||||||
XCTAssertFalse(fs.files.keys.contains(path), file: file, line: line)
|
XCTAssertFalse(fs.files.keys.contains(path), file: file, line: line)
|
||||||
}
|
}
|
||||||
@@ -34,7 +32,7 @@ class FeatureTestCase: XCTestCase {
|
|||||||
contents: String,
|
contents: String,
|
||||||
file: StaticString = #filePath,
|
file: StaticString = #filePath,
|
||||||
line: UInt = #line,
|
line: UInt = #line,
|
||||||
fs: TestableFileSystem
|
in fs: TestableFileSystem
|
||||||
) {
|
) {
|
||||||
XCTAssertEqual(contents, fs.files[path]?.content, file: file, line: line)
|
XCTAssertEqual(contents, fs.files[path]?.content, file: file, line: line)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,39 +9,36 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
final class InternalSwitcherTest: FeatureTestCase {
|
final class InternalSwitcherTest: FeatureTestCase {
|
||||||
|
|
||||||
public func testDefaultPhpFpmPoolIsMoved() async {
|
public func testDefaultPhpFpmPoolIsMoved() async {
|
||||||
ActiveFileSystem.useTestable([
|
let c = Container.fake(files: [
|
||||||
"/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf": .fake(.text)
|
"/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf": .fake(.text)
|
||||||
])
|
]), fs = c.filesystem as! TestableFileSystem
|
||||||
|
|
||||||
let outcome = await InternalSwitcher().disableDefaultPhpFpmPool("8.1")
|
let outcome = await InternalSwitcher(container: c).disableDefaultPhpFpmPool("8.1")
|
||||||
XCTAssertTrue(outcome)
|
XCTAssertTrue(outcome)
|
||||||
|
|
||||||
assertFileSystemHas("/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon")
|
assertFileSystemHas("/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon", in: fs)
|
||||||
assertFileSystemDoesNotHave("/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf")
|
assertFileSystemDoesNotHave("/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf", in: fs)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func testExistingDisabledByPhpMonFileIsRemoved() async {
|
public func testExistingDisabledByPhpMonFileIsRemoved() async {
|
||||||
ActiveFileSystem.useTestable([
|
let c = Container.fake(files: [
|
||||||
"/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf": .fake(.text, "system generated"),
|
"/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf": .fake(.text, "system generated"),
|
||||||
"/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon": .fake(.text, "phpmon generated")
|
"/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon": .fake(.text, "phpmon generated")
|
||||||
])
|
]), fs = c.filesystem as! TestableFileSystem
|
||||||
|
|
||||||
assertFileHasContents(
|
assertFileHasContents("/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon",
|
||||||
"/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon",
|
contents: "phpmon generated", in: fs)
|
||||||
contents: "phpmon generated"
|
|
||||||
)
|
|
||||||
|
|
||||||
let outcome = await InternalSwitcher().disableDefaultPhpFpmPool("8.1")
|
let outcome = await InternalSwitcher(container: c).disableDefaultPhpFpmPool("8.1")
|
||||||
XCTAssertTrue(outcome)
|
XCTAssertTrue(outcome)
|
||||||
|
|
||||||
assertFileSystemHas("/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon")
|
assertFileSystemHas("/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon", in: fs)
|
||||||
assertFileSystemDoesNotHave("/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf")
|
assertFileSystemDoesNotHave("/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf", in: fs)
|
||||||
|
|
||||||
assertFileHasContents(
|
assertFileHasContents(
|
||||||
"/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon",
|
"/opt/homebrew/etc/php/8.1/php-fpm.d/www.conf.disabled-by-phpmon",
|
||||||
contents: "system generated"
|
contents: "system generated", in: fs
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ import Testing
|
|||||||
|
|
||||||
struct CommandTest {
|
struct CommandTest {
|
||||||
@Test func determinePhpVersion() {
|
@Test func determinePhpVersion() {
|
||||||
let version = Command.execute(
|
let container = Container.real()
|
||||||
path: Paths.php,
|
|
||||||
|
let version = container.command.execute(
|
||||||
|
path: container.paths.php,
|
||||||
arguments: ["-v"],
|
arguments: ["-v"],
|
||||||
trimNewlines: false
|
trimNewlines: false
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,8 +9,14 @@
|
|||||||
import Testing
|
import Testing
|
||||||
|
|
||||||
struct BytePhpPreferenceTest {
|
struct BytePhpPreferenceTest {
|
||||||
|
var container: Container
|
||||||
|
|
||||||
|
init () async throws {
|
||||||
|
container = Container.real()
|
||||||
|
}
|
||||||
|
|
||||||
@Test func can_extract_memory_value() throws {
|
@Test func can_extract_memory_value() throws {
|
||||||
let pref = BytePhpPreference(key: "memory_limit")
|
let pref = BytePhpPreference(container, key: "memory_limit")
|
||||||
|
|
||||||
#expect(pref.internalValue == "512M")
|
#expect(pref.internalValue == "512M")
|
||||||
#expect(pref.unit == .megabyte)
|
#expect(pref.unit == .megabyte)
|
||||||
|
|||||||
@@ -11,9 +11,14 @@ import Foundation
|
|||||||
|
|
||||||
@Suite(.serialized)
|
@Suite(.serialized)
|
||||||
struct CaskFileParserTest {
|
struct CaskFileParserTest {
|
||||||
|
var container: Container
|
||||||
|
|
||||||
init() async throws {
|
init() async throws {
|
||||||
ActiveShell.useSystem()
|
container = Container.real()
|
||||||
|
}
|
||||||
|
|
||||||
|
var Shell: ShellProtocol {
|
||||||
|
return container.shell
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Test Files
|
// MARK: - Test Files
|
||||||
@@ -22,7 +27,7 @@ struct CaskFileParserTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_extract_fields_from_cask_file() async throws {
|
@Test func can_extract_fields_from_cask_file() async throws {
|
||||||
guard let caskFile = await CaskFile.from(url: CaskFileParserTest.exampleFilePath) else {
|
guard let caskFile = await CaskFile.from(container, url: CaskFileParserTest.exampleFilePath) else {
|
||||||
Issue.record("The CaskFile could not be parsed, check the log for more info")
|
Issue.record("The CaskFile could not be parsed, check the log for more info")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -48,7 +53,7 @@ struct CaskFileParserTest {
|
|||||||
@Test func can_extract_fields_from_remote_cask_file() async throws {
|
@Test func can_extract_fields_from_remote_cask_file() async throws {
|
||||||
let url = URL(string: "https://raw.githubusercontent.com/nicoverbruggen/homebrew-cask/master/Casks/phpmon.rb")!
|
let url = URL(string: "https://raw.githubusercontent.com/nicoverbruggen/homebrew-cask/master/Casks/phpmon.rb")!
|
||||||
|
|
||||||
guard let caskFile = await CaskFile.from(url: url) else {
|
guard let caskFile = await CaskFile.from(container, url: url) else {
|
||||||
Issue.record("The remote CaskFile could not be parsed, check the log for more info")
|
Issue.record("The remote CaskFile could not be parsed, check the log for more info")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,28 +10,32 @@ import Testing
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct ExtensionEnumeratorTest {
|
struct ExtensionEnumeratorTest {
|
||||||
|
var container: Container
|
||||||
|
|
||||||
init() async throws {
|
init() async throws {
|
||||||
ActiveFileSystem.useTestable([
|
let paths = Paths(container: Container.fake())
|
||||||
"\(Paths.tapPath)/shivammathur/homebrew-extensions/Formula/xdebug@8.1.rb": .fake(.text, "<test>"),
|
|
||||||
"\(Paths.tapPath)/shivammathur/homebrew-extensions/Formula/xdebug@8.2.rb": .fake(.text, "<test>"),
|
container = Container.fake(files: [
|
||||||
"\(Paths.tapPath)/shivammathur/homebrew-extensions/Formula/xdebug@8.3.rb": .fake(.text, "<test>"),
|
"\(paths.tapPath)/shivammathur/homebrew-extensions/Formula/xdebug@8.1.rb": .fake(.text, "<test>"),
|
||||||
"\(Paths.tapPath)/shivammathur/homebrew-extensions/Formula/xdebug@8.4.rb": .fake(.text, "<test>")
|
"\(paths.tapPath)/shivammathur/homebrew-extensions/Formula/xdebug@8.2.rb": .fake(.text, "<test>"),
|
||||||
|
"\(paths.tapPath)/shivammathur/homebrew-extensions/Formula/xdebug@8.3.rb": .fake(.text, "<test>"),
|
||||||
|
"\(paths.tapPath)/shivammathur/homebrew-extensions/Formula/xdebug@8.4.rb": .fake(.text, "<test>")
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_read_formulae() throws {
|
@Test func can_read_formulae() throws {
|
||||||
let directory = "\(Paths.tapPath)/shivammathur/homebrew-extensions/Formula"
|
let directory = "\(container.paths.tapPath)/shivammathur/homebrew-extensions/Formula"
|
||||||
let files = try FileSystem.getShallowContentsOfDirectory(directory)
|
let files = try container.filesystem.getShallowContentsOfDirectory(directory)
|
||||||
|
|
||||||
#expect(Set(files) == Set(["xdebug@8.1.rb", "xdebug@8.2.rb", "xdebug@8.3.rb", "xdebug@8.4.rb"]))
|
#expect(Set(files) == Set(["xdebug@8.1.rb", "xdebug@8.2.rb", "xdebug@8.3.rb", "xdebug@8.4.rb"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_parse_formulae_based_on_syntax() throws {
|
@Test func can_parse_formulae_based_on_syntax() throws {
|
||||||
let formulae = BrewTapFormulae.from(tap: "shivammathur/homebrew-extensions")
|
let formulae = BrewTapFormulae.from(container, tap: "shivammathur/homebrew-extensions")
|
||||||
|
|
||||||
#expect(formulae["8.1"] == [BrewPhpExtension(path: "/", name: "xdebug", phpVersion: "8.1")])
|
#expect(formulae["8.1"] == [BrewPhpExtension(container, path: "/", name: "xdebug", phpVersion: "8.1")])
|
||||||
#expect(formulae["8.2"] == [BrewPhpExtension(path: "/", name: "xdebug", phpVersion: "8.2")])
|
#expect(formulae["8.2"] == [BrewPhpExtension(container, path: "/", name: "xdebug", phpVersion: "8.2")])
|
||||||
#expect(formulae["8.3"] == [BrewPhpExtension(path: "/", name: "xdebug", phpVersion: "8.3")])
|
#expect(formulae["8.3"] == [BrewPhpExtension(container, path: "/", name: "xdebug", phpVersion: "8.3")])
|
||||||
#expect(formulae["8.4"] == [BrewPhpExtension(path: "/", name: "xdebug", phpVersion: "8.4")])
|
#expect(formulae["8.4"] == [BrewPhpExtension(container, path: "/", name: "xdebug", phpVersion: "8.4")])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,12 +53,12 @@ struct HomebrewPackageTest {
|
|||||||
/// or the JSON API of the Homebrew output may have changed.
|
/// or the JSON API of the Homebrew output may have changed.
|
||||||
@Test(.disabled("Uses system command; enable at your own risk"))
|
@Test(.disabled("Uses system command; enable at your own risk"))
|
||||||
func can_parse_services_json_from_cli_output() async throws {
|
func can_parse_services_json_from_cli_output() async throws {
|
||||||
ActiveShell.useSystem()
|
let container = Container.real()
|
||||||
|
|
||||||
let services = try! JSONDecoder().decode(
|
let services = try! JSONDecoder().decode(
|
||||||
[HomebrewService].self,
|
[HomebrewService].self,
|
||||||
from: await Shell.pipe(
|
from: await container.shell.pipe(
|
||||||
"sudo \(Paths.brew) services info --all --json"
|
"sudo \(container.paths.brew) services info --all --json"
|
||||||
).out.data(using: .utf8)!
|
).out.data(using: .utf8)!
|
||||||
).filter({ service in
|
).filter({ service in
|
||||||
return ["php", "nginx", "dnsmasq"].contains(service.name)
|
return ["php", "nginx", "dnsmasq"].contains(service.name)
|
||||||
@@ -76,12 +76,11 @@ struct HomebrewPackageTest {
|
|||||||
/// or the JSON API of the Homebrew output may have changed.
|
/// or the JSON API of the Homebrew output may have changed.
|
||||||
@Test(.disabled("Uses system command; enable at your own risk"))
|
@Test(.disabled("Uses system command; enable at your own risk"))
|
||||||
func can_load_extension_json_from_cli_output() async throws {
|
func can_load_extension_json_from_cli_output() async throws {
|
||||||
|
let container = Container.real()
|
||||||
ActiveShell.useSystem()
|
|
||||||
|
|
||||||
let package = try! JSONDecoder().decode(
|
let package = try! JSONDecoder().decode(
|
||||||
[HomebrewPackage].self,
|
[HomebrewPackage].self,
|
||||||
from: await Shell.pipe("\(Paths.brew) info php --json").out.data(using: .utf8)!
|
from: await container.shell.pipe("\(container.paths.brew) info php --json").out.data(using: .utf8)!
|
||||||
).first!
|
).first!
|
||||||
|
|
||||||
#expect(package.full_name == "php")
|
#expect(package.full_name == "php")
|
||||||
|
|||||||
@@ -10,42 +10,45 @@ import Testing
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct HomebrewUpgradableTest {
|
struct HomebrewUpgradableTest {
|
||||||
|
var container: Container
|
||||||
|
init() throws {
|
||||||
|
container = Container.fake(
|
||||||
|
shell: [
|
||||||
|
"/opt/homebrew/bin/brew update >/dev/null && /opt/homebrew/bin/brew outdated --json --formulae"
|
||||||
|
: .instant(try! String(contentsOf: Self.outdatedFileUrl)),
|
||||||
|
"/opt/homebrew/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
||||||
|
: .instant("/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini"),
|
||||||
|
"/opt/homebrew/opt/php@8.1.16/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
||||||
|
: .instant("/opt/homebrew/etc/php/8.1/conf.d/php-memory-limits.ini"),
|
||||||
|
"/opt/homebrew/opt/php@8.2.3/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
||||||
|
: .instant("/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini"),
|
||||||
|
"/opt/homebrew/opt/php@7.4.11/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
||||||
|
: .instant("/opt/homebrew/etc/php/7.4/conf.d/php-memory-limits.ini")
|
||||||
|
],
|
||||||
|
files: [
|
||||||
|
"/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini": .fake(.text),
|
||||||
|
"/opt/homebrew/etc/php/8.1/conf.d/php-memory-limits.ini": .fake(.text),
|
||||||
|
"/opt/homebrew/etc/php/7.4/conf.d/php-memory-limits.ini": .fake(.text)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
static var outdatedFileUrl: URL {
|
static var outdatedFileUrl: URL {
|
||||||
return TestBundle.url(forResource: "brew-outdated", withExtension: "json")!
|
return TestBundle.url(forResource: "brew-outdated", withExtension: "json")!
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func upgradable_php_versions_can_be_determined() async throws {
|
@Test func upgradable_php_versions_can_be_determined() async throws {
|
||||||
// Do not execute production cli commands
|
|
||||||
ActiveShell.useTestable([
|
|
||||||
"/opt/homebrew/bin/brew update >/dev/null && /opt/homebrew/bin/brew outdated --json --formulae"
|
|
||||||
: .instant(try! String(contentsOf: Self.outdatedFileUrl)),
|
|
||||||
"/opt/homebrew/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
|
||||||
: .instant("/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini"),
|
|
||||||
"/opt/homebrew/opt/php@8.1.16/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
|
||||||
: .instant("/opt/homebrew/etc/php/8.1/conf.d/php-memory-limits.ini"),
|
|
||||||
"/opt/homebrew/opt/php@8.2.3/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
|
||||||
: .instant("/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini"),
|
|
||||||
"/opt/homebrew/opt/php@7.4.11/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
|
||||||
: .instant("/opt/homebrew/etc/php/7.4/conf.d/php-memory-limits.ini")
|
|
||||||
])
|
|
||||||
|
|
||||||
// Do not read our production files
|
|
||||||
ActiveFileSystem.useTestable([
|
|
||||||
"/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini": .fake(.text),
|
|
||||||
"/opt/homebrew/etc/php/8.1/conf.d/php-memory-limits.ini": .fake(.text),
|
|
||||||
"/opt/homebrew/etc/php/7.4/conf.d/php-memory-limits.ini": .fake(.text)
|
|
||||||
])
|
|
||||||
|
|
||||||
// This config file assumes our PHP alias (`php`) is v8.2
|
// This config file assumes our PHP alias (`php`) is v8.2
|
||||||
PhpEnvironments.brewPhpAlias = "8.2"
|
PhpEnvironments.brewPhpAlias = "8.2"
|
||||||
let env = App.shared.container.phpEnvs
|
let env = container.phpEnvs!
|
||||||
env.cachedPhpInstallations = [
|
env.cachedPhpInstallations = [
|
||||||
"8.1": PhpInstallation("8.1.16"),
|
"8.1": PhpInstallation(container, "8.1.16"),
|
||||||
"8.2": PhpInstallation("8.2.3"),
|
"8.2": PhpInstallation(container, "8.2.3"),
|
||||||
"7.4": PhpInstallation("7.4.11")
|
"7.4": PhpInstallation(container, "7.4.11")
|
||||||
]
|
]
|
||||||
|
|
||||||
let data = await BrewPhpFormulaeHandler().loadPhpVersions(loadOutdated: true)
|
let data = await BrewPhpFormulaeHandler(container: container)
|
||||||
|
.loadPhpVersions(loadOutdated: true)
|
||||||
|
|
||||||
#expect(true == data.contains(where: { formula in
|
#expect(true == data.contains(where: { formula in
|
||||||
formula.installedVersion == "8.1.16" && formula.upgradeVersion == "8.1.17"
|
formula.installedVersion == "8.1.16" && formula.upgradeVersion == "8.1.17"
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ import Testing
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct NginxConfigurationTest {
|
struct NginxConfigurationTest {
|
||||||
|
var container: Container
|
||||||
|
|
||||||
|
init () async throws {
|
||||||
|
container = Container.real()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Test Files
|
// MARK: - Test Files
|
||||||
|
|
||||||
@@ -36,33 +41,33 @@ struct NginxConfigurationTest {
|
|||||||
// MARK: - Tests
|
// MARK: - Tests
|
||||||
|
|
||||||
@Test func can_determine_site_name_and_tld() throws {
|
@Test func can_determine_site_name_and_tld() throws {
|
||||||
#expect("nginx-site" == NginxConfigurationFile.from(filePath: Self.regularUrl.path)?.domain)
|
#expect("nginx-site" == NginxConfigurationFile.from(container, filePath: Self.regularUrl.path)?.domain)
|
||||||
#expect("test" == NginxConfigurationFile.from(filePath: Self.regularUrl.path)?.tld)
|
#expect("test" == NginxConfigurationFile.from(container, filePath: Self.regularUrl.path)?.tld)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_determine_isolation() throws {
|
@Test func can_determine_isolation() throws {
|
||||||
#expect(nil == NginxConfigurationFile.from(filePath: Self.regularUrl.path)?.isolatedVersion)
|
#expect(nil == NginxConfigurationFile.from(container, filePath: Self.regularUrl.path)?.isolatedVersion)
|
||||||
#expect("8.1" == NginxConfigurationFile.from(filePath: Self.isolatedUrl.path)?.isolatedVersion)
|
#expect("8.1" == NginxConfigurationFile.from(container, filePath: Self.isolatedUrl.path)?.isolatedVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_determine_proxy() throws {
|
@Test func can_determine_proxy() throws {
|
||||||
let proxied = NginxConfigurationFile.from(filePath: Self.proxyUrl.path)!
|
let proxied = NginxConfigurationFile.from(container, filePath: Self.proxyUrl.path)!
|
||||||
#expect(proxied.contents.contains("# valet stub: proxy.valet.conf"))
|
#expect(proxied.contents.contains("# valet stub: proxy.valet.conf"))
|
||||||
#expect("http://127.0.0.1:90" == proxied.proxy)
|
#expect("http://127.0.0.1:90" == proxied.proxy)
|
||||||
|
|
||||||
let normal = NginxConfigurationFile.from(filePath: Self.regularUrl.path)!
|
let normal = NginxConfigurationFile.from(container, filePath: Self.regularUrl.path)!
|
||||||
#expect(false == normal.contents.contains("# valet stub: proxy.valet.conf"))
|
#expect(false == normal.contents.contains("# valet stub: proxy.valet.conf"))
|
||||||
#expect(nil == normal.proxy)
|
#expect(nil == normal.proxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_determine_secured_proxy() throws {
|
@Test func can_determine_secured_proxy() throws {
|
||||||
let proxied = NginxConfigurationFile.from(filePath: Self.secureProxyUrl.path)!
|
let proxied = NginxConfigurationFile.from(container, filePath: Self.secureProxyUrl.path)!
|
||||||
#expect(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
|
#expect(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
|
||||||
#expect("http://127.0.0.1:90" == proxied.proxy)
|
#expect("http://127.0.0.1:90" == proxied.proxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_determine_proxy_with_custom_tld() throws {
|
@Test func can_determine_proxy_with_custom_tld() throws {
|
||||||
let proxied = NginxConfigurationFile.from(filePath: Self.customTldProxyUrl.path)!
|
let proxied = NginxConfigurationFile.from(container, filePath: Self.customTldProxyUrl.path)!
|
||||||
#expect(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
|
#expect(proxied.contents.contains("# valet stub: secure.proxy.valet.conf"))
|
||||||
#expect("http://localhost:8080" == proxied.proxy)
|
#expect("http://localhost:8080" == proxied.proxy)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,21 +11,25 @@ import Foundation
|
|||||||
|
|
||||||
@Suite(.serialized)
|
@Suite(.serialized)
|
||||||
class PhpConfigurationFileTest {
|
class PhpConfigurationFileTest {
|
||||||
|
var container: Container
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.container = Container.real()
|
||||||
|
}
|
||||||
|
|
||||||
static var phpIniFileUrl: URL {
|
static var phpIniFileUrl: URL {
|
||||||
return TestBundle.url(forResource: "php", withExtension: "ini")!
|
return TestBundle.url(forResource: "php", withExtension: "ini")!
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_load_extension() throws {
|
@Test func can_load_extension() throws {
|
||||||
ActiveFileSystem.useSystem()
|
let iniFile = PhpConfigurationFile.from(container, filePath: Self.phpIniFileUrl.path)
|
||||||
let iniFile = PhpConfigurationFile.from(filePath: Self.phpIniFileUrl.path)
|
|
||||||
|
|
||||||
#expect(iniFile != nil)
|
#expect(iniFile != nil)
|
||||||
#expect(!iniFile!.extensions.isEmpty)
|
#expect(!iniFile!.extensions.isEmpty)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_check_key_existence() throws {
|
@Test func can_check_key_existence() throws {
|
||||||
print(Self.phpIniFileUrl.path)
|
let iniFile = PhpConfigurationFile.from(container, filePath: Self.phpIniFileUrl.path)!
|
||||||
let iniFile = PhpConfigurationFile.from(filePath: Self.phpIniFileUrl.path)!
|
|
||||||
|
|
||||||
#expect(iniFile.has(key: "error_reporting"))
|
#expect(iniFile.has(key: "error_reporting"))
|
||||||
#expect(iniFile.has(key: "display_errors"))
|
#expect(iniFile.has(key: "display_errors"))
|
||||||
@@ -33,7 +37,7 @@ class PhpConfigurationFileTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_check_key_value() throws {
|
@Test func can_check_key_value() throws {
|
||||||
let iniFile = PhpConfigurationFile.from(filePath: Self.phpIniFileUrl.path)!
|
let iniFile = PhpConfigurationFile.from(container, filePath: Self.phpIniFileUrl.path)!
|
||||||
|
|
||||||
#expect(iniFile.get(for: "error_reporting") != nil)
|
#expect(iniFile.get(for: "error_reporting") != nil)
|
||||||
#expect(iniFile.get(for: "error_reporting") == "E_ALL")
|
#expect(iniFile.get(for: "error_reporting") == "E_ALL")
|
||||||
@@ -46,8 +50,7 @@ class PhpConfigurationFileTest {
|
|||||||
let destination = Utility
|
let destination = Utility
|
||||||
.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
|
.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
|
||||||
|
|
||||||
let configurationFile = PhpConfigurationFile
|
let configurationFile = PhpConfigurationFile.from(container, filePath: destination.path)!
|
||||||
.from(filePath: destination.path)!
|
|
||||||
|
|
||||||
// 0. Verify the original value
|
// 0. Verify the original value
|
||||||
#expect(configurationFile.get(for: "error_reporting") == "E_ALL")
|
#expect(configurationFile.get(for: "error_reporting") == "E_ALL")
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ import Foundation
|
|||||||
|
|
||||||
@Suite(.serialized)
|
@Suite(.serialized)
|
||||||
struct PhpExtensionTest {
|
struct PhpExtensionTest {
|
||||||
|
var container: Container
|
||||||
|
|
||||||
init () async throws {
|
init () async throws {
|
||||||
ActiveShell.useSystem()
|
container = Container.real()
|
||||||
}
|
}
|
||||||
|
|
||||||
static var phpIniFileUrl: URL {
|
static var phpIniFileUrl: URL {
|
||||||
@@ -20,13 +22,13 @@ struct PhpExtensionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test func can_load_extension() throws {
|
@Test func can_load_extension() throws {
|
||||||
let extensions = PhpExtension.from(filePath: Self.phpIniFileUrl.path)
|
let extensions = PhpExtension.from(container, filePath: Self.phpIniFileUrl.path)
|
||||||
|
|
||||||
#expect(!extensions.isEmpty)
|
#expect(!extensions.isEmpty)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func extension_name_is_correct() throws {
|
@Test func extension_name_is_correct() throws {
|
||||||
let extensions = PhpExtension.from(filePath: Self.phpIniFileUrl.path)
|
let extensions = PhpExtension.from(container, filePath: Self.phpIniFileUrl.path)
|
||||||
|
|
||||||
let extensionNames = extensions.map { (ext) -> String in
|
let extensionNames = extensions.map { (ext) -> String in
|
||||||
return ext.name
|
return ext.name
|
||||||
@@ -45,7 +47,7 @@ struct PhpExtensionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test func extension_status_is_correct() throws {
|
@Test func extension_status_is_correct() throws {
|
||||||
let extensions = PhpExtension.from(filePath: Self.phpIniFileUrl.path)
|
let extensions = PhpExtension.from(container, filePath: Self.phpIniFileUrl.path)
|
||||||
|
|
||||||
// xdebug should be enabled
|
// xdebug should be enabled
|
||||||
#expect(extensions[0].enabled == true)
|
#expect(extensions[0].enabled == true)
|
||||||
@@ -56,7 +58,7 @@ struct PhpExtensionTest {
|
|||||||
|
|
||||||
@Test func toggle_works_as_expected() async throws {
|
@Test func toggle_works_as_expected() async throws {
|
||||||
let destination = Utility.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
|
let destination = Utility.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
|
||||||
let extensions = PhpExtension.from(filePath: destination.path)
|
let extensions = PhpExtension.from(container, filePath: destination.path)
|
||||||
#expect(extensions.count == 6)
|
#expect(extensions.count == 6)
|
||||||
|
|
||||||
// Try to disable xdebug (should be detected first)!
|
// Try to disable xdebug (should be detected first)!
|
||||||
@@ -71,6 +73,6 @@ struct PhpExtensionTest {
|
|||||||
#expect(file.contains("; zend_extension=\"xdebug.so\""))
|
#expect(file.contains("; zend_extension=\"xdebug.so\""))
|
||||||
|
|
||||||
// Make sure if we load the data again, it's disabled
|
// Make sure if we load the data again, it's disabled
|
||||||
#expect(PhpExtension.from(filePath: destination.path).first!.enabled == false)
|
#expect(PhpExtension.from(container, filePath: destination.path).first!.enabled == false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ struct RealFileSystemTest {
|
|||||||
"\(temporaryDirectory)/brew/etc/lib/c"
|
"\(temporaryDirectory)/brew/etc/lib/c"
|
||||||
)
|
)
|
||||||
|
|
||||||
let contents = try! FileSystem.getShallowContentsOfDirectory("\(temporaryDirectory)/brew/etc/lib/c")
|
let contents = try! filesystem.getShallowContentsOfDirectory("\(temporaryDirectory)/brew/etc/lib/c")
|
||||||
#expect([] == contents)
|
#expect([] == contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ import Foundation
|
|||||||
|
|
||||||
@Suite(.serialized)
|
@Suite(.serialized)
|
||||||
struct TestableFileSystemTest {
|
struct TestableFileSystemTest {
|
||||||
|
var container: Container
|
||||||
init() throws {
|
init() throws {
|
||||||
ActiveFileSystem.useTestable([
|
container = Container.fake(files: [
|
||||||
"/home/user/bin/foo": .fake(.binary),
|
"/home/user/bin/foo": .fake(.binary),
|
||||||
"/home/user/docs": .fake(.symlink, "/home/user/documents"),
|
"/home/user/docs": .fake(.symlink, "/home/user/documents"),
|
||||||
"/home/user/documents/script.sh": .fake(.text, "echo 'cool';"),
|
"/home/user/documents/script.sh": .fake(.text, "echo 'cool';"),
|
||||||
@@ -22,6 +23,10 @@ struct TestableFileSystemTest {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var FileSystem: FileSystemProtocol {
|
||||||
|
return container.filesystem
|
||||||
|
}
|
||||||
|
|
||||||
@Test func testable_fs_is_in_use() {
|
@Test func testable_fs_is_in_use() {
|
||||||
#expect(FileSystem is TestableFileSystem)
|
#expect(FileSystem is TestableFileSystem)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,15 @@ import Foundation
|
|||||||
|
|
||||||
@Suite(.serialized)
|
@Suite(.serialized)
|
||||||
struct RealShellTest {
|
struct RealShellTest {
|
||||||
|
var container: Container
|
||||||
|
|
||||||
init() async throws {
|
init() async throws {
|
||||||
// Reset to the default shell
|
// Reset to the default shell
|
||||||
ActiveShell.useSystem()
|
container = Container.real()
|
||||||
|
}
|
||||||
|
|
||||||
|
var Shell: ShellProtocol {
|
||||||
|
return container.shell
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func system_shell_is_default() async {
|
@Test func system_shell_is_default() async {
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ struct TestableShellTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test func fake_shell_has_path() {
|
@Test func fake_shell_has_path() {
|
||||||
ActiveShell.useTestable([:])
|
let container = Container.fake()
|
||||||
|
|
||||||
#expect(Shell.PATH == "/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin")
|
#expect(container.shell.PATH == "/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import Foundation
|
|||||||
|
|
||||||
struct TestableConfigurationTest {
|
struct TestableConfigurationTest {
|
||||||
@Test func configuration_can_be_saved_as_json() async {
|
@Test func configuration_can_be_saved_as_json() async {
|
||||||
|
let container = Container.real()
|
||||||
|
|
||||||
// WORKING
|
// WORKING
|
||||||
var configuration = TestableConfigurations.working
|
var configuration = TestableConfigurations.working
|
||||||
|
|
||||||
@@ -39,8 +41,8 @@ struct TestableConfigurationTest {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Verify that the files were written to disk
|
// Verify that the files were written to disk
|
||||||
#expect(FileSystem.fileExists(NSHomeDirectory() + "/.phpmon_fconf_working.json"))
|
#expect(container.filesystem.fileExists(NSHomeDirectory() + "/.phpmon_fconf_working.json"))
|
||||||
#expect(FileSystem.fileExists(NSHomeDirectory() + "/.phpmon_fconf_working_no_valet.json"))
|
#expect(container.filesystem.fileExists(NSHomeDirectory() + "/.phpmon_fconf_working_no_valet.json"))
|
||||||
#expect(FileSystem.fileExists(NSHomeDirectory() + "/.phpmon_fconf_broken.json"))
|
#expect(container.filesystem.fileExists(NSHomeDirectory() + "/.phpmon_fconf_broken.json"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,10 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
class PhpVersionDetectionTest: XCTestCase {
|
class PhpVersionDetectionTest: XCTestCase {
|
||||||
|
|
||||||
func test_can_detect_valid_php_versions() async throws {
|
func test_can_detect_valid_php_versions() async throws {
|
||||||
let outcome = await App.shared.container.phpEnvs.extractPhpVersions(
|
let container = Container.real()
|
||||||
|
|
||||||
|
let outcome = await container.phpEnvs.extractPhpVersions(
|
||||||
from: [
|
from: [
|
||||||
"", // empty lines should be omitted
|
"", // empty lines should be omitted
|
||||||
"php@8.0",
|
"php@8.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user