diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 34ad757..3bcae17 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -220,8 +220,8 @@ C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */; }; C4B5853E2770FE3900DA4FBE /* Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853B2770FE3900DA4FBE /* Paths.swift */; }; C4B5853F2770FE3900DA4FBE /* Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853B2770FE3900DA4FBE /* Paths.swift */; }; - C4B585442770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; }; - C4B585452770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; }; + C4B585442770FE3900DA4FBE /* RealCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* RealCommand.swift */; }; + C4B585452770FE3900DA4FBE /* RealCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* RealCommand.swift */; }; C4B6091A2853AAD300C95265 /* SectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B609192853AAD300C95265 /* SectionHeaderView.swift */; }; C4B6091D2853AB9700C95265 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B6091C2853AB9700C95265 /* ServicesView.swift */; }; C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */; }; @@ -278,6 +278,12 @@ C4E0F7EE27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */; }; C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E4404527C56F4700D225E1 /* ValetSite.swift */; }; C4E4404727C56F4700D225E1 /* ValetSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E4404527C56F4700D225E1 /* ValetSite.swift */; }; + C4E49DE728F764050026AC4E /* ActiveCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E49DE628F764050026AC4E /* ActiveCommand.swift */; }; + C4E49DE828F764050026AC4E /* ActiveCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E49DE628F764050026AC4E /* ActiveCommand.swift */; }; + C4E49DEA28F7643D0026AC4E /* CommandProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E49DE928F7643D0026AC4E /* CommandProtocol.swift */; }; + C4E49DEB28F7643D0026AC4E /* CommandProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E49DE928F7643D0026AC4E /* CommandProtocol.swift */; }; + C4E49DED28F764A00026AC4E /* TestableCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E49DEC28F764A00026AC4E /* TestableCommand.swift */; }; + C4E49DEE28F764A00026AC4E /* TestableCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E49DEC28F764A00026AC4E /* TestableCommand.swift */; }; C4E9D2C02878B336008FFDAD /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E9D2BF2878B336008FFDAD /* OnboardingView.swift */; }; C4EB53E528551F9B006F9937 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EB53E428551F9B006F9937 /* HeaderView.swift */; }; C4EB53E728553117006F9937 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EB53E628553117006F9937 /* ArrayExtension.swift */; }; @@ -465,7 +471,7 @@ C4B5635D276AB09000F12CCB /* VersionExtractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionExtractor.swift; sourceTree = ""; }; C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionExtractorTest.swift; sourceTree = ""; }; C4B5853B2770FE3900DA4FBE /* Paths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Paths.swift; sourceTree = ""; }; - C4B5853D2770FE3900DA4FBE /* Command.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; + C4B5853D2770FE3900DA4FBE /* RealCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RealCommand.swift; sourceTree = ""; }; C4B609192853AAD300C95265 /* SectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderView.swift; sourceTree = ""; }; C4B6091C2853AB9700C95265 /* ServicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesView.swift; sourceTree = ""; }; C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+MenuOutlets.swift"; sourceTree = ""; }; @@ -498,6 +504,9 @@ C4DEB7D327A5D60B00834718 /* Stats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stats.swift; sourceTree = ""; }; C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSWindowExtension.swift; sourceTree = ""; }; C4E4404527C56F4700D225E1 /* ValetSite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetSite.swift; sourceTree = ""; }; + C4E49DE628F764050026AC4E /* ActiveCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveCommand.swift; sourceTree = ""; }; + C4E49DE928F7643D0026AC4E /* CommandProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandProtocol.swift; sourceTree = ""; }; + C4E49DEC28F764A00026AC4E /* TestableCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableCommand.swift; sourceTree = ""; }; C4E713562570150F00007428 /* SECURITY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = SECURITY.md; sourceTree = ""; }; C4E713572570151400007428 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = ""; }; C4E9D2BF2878B336008FFDAD /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = ""; }; @@ -663,7 +672,6 @@ C415D3B62770F294005EF286 /* Actions.swift */, C4EE188322D3386B00E126E5 /* Constants.swift */, C4EC1E72279DFCF40010F296 /* Events.swift */, - C4B5853D2770FE3900DA4FBE /* Command.swift */, C4B5853B2770FE3900DA4FBE /* Paths.swift */, C4C1019A27C65C6F001FACC2 /* Process.swift */, C40C7F2F27722E8D00DDDCDC /* Logger.swift */, @@ -991,6 +999,7 @@ C4F787A728EF812600790735 /* Testables */, C4F787A628EF811000790735 /* Shell */, C4C8900128F0E27900CE5E97 /* Filesystem */, + C4E49DE528F763E20026AC4E /* Command */, C40C7F2127721F7300DDDCDC /* Core */, 54B20EDF263AA22C00D3250E /* PHP */, C44CCD4327AFE93300CE40E5 /* Errors */, @@ -1162,6 +1171,16 @@ path = Switcher; sourceTree = ""; }; + C4E49DE528F763E20026AC4E /* Command */ = { + isa = PBXGroup; + children = ( + C4E49DE628F764050026AC4E /* ActiveCommand.swift */, + C4B5853D2770FE3900DA4FBE /* RealCommand.swift */, + C4E49DE928F7643D0026AC4E /* CommandProtocol.swift */, + ); + path = Command; + sourceTree = ""; + }; C4E9D2BE2878B32D008FFDAD /* Onboarding */ = { isa = PBXGroup; children = ( @@ -1221,6 +1240,7 @@ C40F505428ECA64E004AD45B /* TestableConfigurations.swift */, C46EBC4928DB966A007ACC74 /* TestableShell.swift */, C4AD38B128ECD9D300FA8D83 /* TestableFileSystem.swift */, + C4E49DEC28F764A00026AC4E /* TestableCommand.swift */, ); path = Testables; sourceTree = ""; @@ -1413,11 +1433,13 @@ C4E0F7ED27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */, C4205A7E27F4D21800191A39 /* ValetProxy.swift in Sources */, C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, + C4E49DE728F764050026AC4E /* ActiveCommand.swift in Sources */, 54FCFD30276C8DA4004CE748 /* HotkeyPreferenceView.swift in Sources */, C450C8C628C919EC002A2B4B /* PreferenceName.swift in Sources */, C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */, C4F2E43A2752F7D00020E974 /* PhpInstallation.swift in Sources */, C4D9F24B280B69E100DCD39A /* AddProxyVC.swift in Sources */, + C4E49DED28F764A00026AC4E /* TestableCommand.swift in Sources */, C4A6957628D23EE300A14CF8 /* EnvironmentManager.swift in Sources */, C41E871A2763D42300161EE0 /* DomainListVC+ContextMenu.swift in Sources */, C40C7F2827721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */, @@ -1433,7 +1455,7 @@ C40FE737282ABA4F00A302C2 /* AppVersion.swift in Sources */, C44A874828905BB000498BC4 /* ProgressVC.swift in Sources */, C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */, - C4B585442770FE3900DA4FBE /* Command.swift in Sources */, + C4B585442770FE3900DA4FBE /* RealCommand.swift in Sources */, C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */, C40C5C9C2846A40600E28255 /* Preset.swift in Sources */, C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */, @@ -1531,6 +1553,7 @@ C4EE188422D3386B00E126E5 /* Constants.swift in Sources */, C493084A279F331F009C240B /* AddSiteVC.swift in Sources */, C4DEB7D427A5D60B00834718 /* Stats.swift in Sources */, + C4E49DEA28F7643D0026AC4E /* CommandProtocol.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1591,6 +1614,7 @@ C46FA98C2822F08F00D78807 /* PhpConfigurationTest.swift in Sources */, C4BF90C127C57C220054E78C /* MainMenu+FixMyValet.swift in Sources */, C4C0E8EB27F88B80002D32A9 /* ValetProxy+Fake.swift in Sources */, + C4E49DEB28F7643D0026AC4E /* CommandProtocol.swift in Sources */, C4F2E4382752F08D0020E974 /* HomebrewDiagnostics.swift in Sources */, C485707428BF454E00539B36 /* ServicesView.swift in Sources */, C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */, @@ -1620,6 +1644,7 @@ C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */, C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */, C415D3E92770F692005EF286 /* AppDelegate+InterApp.swift in Sources */, + C4E49DEE28F764A00026AC4E /* TestableCommand.swift in Sources */, C484437C2804BB560041A78A /* ValetProxyScanner.swift in Sources */, C4AF9F78275447F100D44ED0 /* ValetConfigurationTest.swift in Sources */, C4CE3BBC27B324250086CA49 /* ComposerWindow.swift in Sources */, @@ -1631,6 +1656,7 @@ 54D9E0B327E4F51E003B9AD9 /* HotKeysController.swift in Sources */, 03E36FE828D9219000636F7F /* ActiveShell.swift in Sources */, C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */, + C4E49DE828F764050026AC4E /* ActiveCommand.swift in Sources */, C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */, C46E20702829D27F00D909D6 /* AppUpdaterCheckTest.swift in Sources */, C485707D28BF45A200539B36 /* WarningView.swift in Sources */, @@ -1660,7 +1686,7 @@ C4C0E8E027F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */, C4AF9F7D275454A900D44ED0 /* ValetVersionExtractorTest.swift in Sources */, C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */, - C4B585452770FE3900DA4FBE /* Command.swift in Sources */, + C4B585452770FE3900DA4FBE /* RealCommand.swift in Sources */, C4F780C525D80B75000DBC97 /* MenuBarImageGenerator.swift in Sources */, C4F780B725D80B5D000DBC97 /* App.swift in Sources */, C4927F0C27B2DFC200C55AFD /* Errors.swift in Sources */, diff --git a/phpmon/Common/Command/ActiveCommand.swift b/phpmon/Common/Command/ActiveCommand.swift new file mode 100644 index 0000000..190e4e7 --- /dev/null +++ b/phpmon/Common/Command/ActiveCommand.swift @@ -0,0 +1,25 @@ +// +// ActiveCommand.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 12/10/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Foundation + +var Command: CommandProtocol { + return ActiveCommand.shared +} + +class ActiveCommand { + static var shared: CommandProtocol = RealCommand() + + public static func useTestable(_ output: [String: String]) { + Self.shared = TestableCommand(commands: output) + } + + public static func useSystem() { + Self.shared = RealCommand() + } +} diff --git a/phpmon/Common/Command/CommandProtocol.swift b/phpmon/Common/Command/CommandProtocol.swift new file mode 100644 index 0000000..49411f0 --- /dev/null +++ b/phpmon/Common/Command/CommandProtocol.swift @@ -0,0 +1,22 @@ +// +// CommandProtocol.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 12/10/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Foundation + +protocol CommandProtocol { + + /** + Immediately executes a command. + + - Parameter path: The path of the command or program to invoke. + - Parameter arguments: A list of arguments that are passed on. + - Parameter trimNewlines: Removes empty new line output. + */ + func execute(path: String, arguments: [String], trimNewlines: Bool) -> String + +} diff --git a/phpmon/Common/Core/Command.swift b/phpmon/Common/Command/RealCommand.swift similarity index 63% rename from phpmon/Common/Core/Command.swift rename to phpmon/Common/Command/RealCommand.swift index d7c8e90..f9a0001 100644 --- a/phpmon/Common/Core/Command.swift +++ b/phpmon/Common/Command/RealCommand.swift @@ -7,16 +7,9 @@ import Cocoa -public class Command { +public class RealCommand: CommandProtocol { - /** - Immediately executes a command. - - - Parameter path: The path of the command or program to invoke. - - Parameter arguments: A list of arguments that are passed on. - - Parameter trimNewlines: Removes empty new line output. - */ - public static func execute(path: String, arguments: [String], trimNewlines: Bool = false) -> String { + public func execute(path: String, arguments: [String], trimNewlines: Bool = false) -> String { let task = Process() task.launchPath = path task.arguments = arguments diff --git a/phpmon/Common/PHP/ActivePhpInstallation.swift b/phpmon/Common/PHP/ActivePhpInstallation.swift index 71dda95..e06fea5 100644 --- a/phpmon/Common/PHP/ActivePhpInstallation.swift +++ b/phpmon/Common/PHP/ActivePhpInstallation.swift @@ -65,7 +65,7 @@ class ActivePhpInstallation { ) // Return a list of .ini files parsed after php.ini - let paths = Command.execute(path: Paths.php, arguments: ["-r", "echo php_ini_scanned_files();"]) + let paths = Command.execute(path: Paths.php, arguments: ["-r", "echo php_ini_scanned_files();"], trimNewlines: false) .replacingOccurrences(of: "\n", with: "") .split(separator: ",") .map { String($0) } @@ -105,7 +105,7 @@ class ActivePhpInstallation { - Parameter key: The key of the `ini` value that needs to be retrieved. For example, you can use `memory_limit`. */ private func getByteCount(key: String) -> String { - let value = Command.execute(path: Paths.php, arguments: ["-r", "echo ini_get('\(key)');"]) + let value = Command.execute(path: Paths.php, arguments: ["-r", "echo ini_get('\(key)');"], trimNewlines: false) // Check if the value is unlimited if value == "-1" { diff --git a/phpmon/Common/PHP/PhpInstallation.swift b/phpmon/Common/PHP/PhpInstallation.swift index 8172760..c8abf99 100644 --- a/phpmon/Common/PHP/PhpInstallation.swift +++ b/phpmon/Common/PHP/PhpInstallation.swift @@ -24,7 +24,8 @@ class PhpInstallation { if FileSystem.fileExists(phpConfigExecutablePath) { let longVersionString = Command.execute( path: phpConfigExecutablePath, - arguments: ["--version"] + arguments: ["--version"], + trimNewlines: false ).trimmingCharacters(in: .whitespacesAndNewlines) // The parser should always work, or the string has to be very unusual. diff --git a/phpmon/Common/Testables/TestableCommand.swift b/phpmon/Common/Testables/TestableCommand.swift new file mode 100644 index 0000000..212e28c --- /dev/null +++ b/phpmon/Common/Testables/TestableCommand.swift @@ -0,0 +1,27 @@ +// +// TestableCommand.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 12/10/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Foundation + +class TestableCommand: CommandProtocol { + init(commands: [String: String]) { + self.commands = commands + } + + var commands: [String: String] + + func execute(path: String, arguments: [String]) -> String { + self.execute(path: path, arguments: arguments, trimNewlines: false) + } + + public func execute(path: String, arguments: [String], trimNewlines: Bool) -> String { + let concatenatedCommand = "\(path) \(arguments.joined(separator: " "))" + assert(commands.keys.contains(concatenatedCommand), "The expected command (\(concatenatedCommand)) was not found") + return self.commands[concatenatedCommand]! + } +} diff --git a/phpmon/Common/Testables/TestableConfigurations.swift b/phpmon/Common/Testables/TestableConfigurations.swift index 31ef899..40444f6 100644 --- a/phpmon/Common/Testables/TestableConfigurations.swift +++ b/phpmon/Common/Testables/TestableConfigurations.swift @@ -12,10 +12,12 @@ struct TestableConfiguration { let architecture: String let filesystem: [String: FakeFile] let shellOutput: [String: BatchFakeShellOutput] + let commandOutput: [String: String] func apply() { ActiveShell.useTestable(shellOutput) ActiveFileSystem.useTestable(filesystem) + ActiveCommand.useTestable(commandOutput) } } @@ -31,7 +33,8 @@ class TestableConfigurations { "id -un" : .instant("username"), "php -v" : .instant(""), "ls /opt/homebrew/opt | grep php" : .instant(""), - ] + ], + commandOutput: [:] ) } @@ -112,6 +115,19 @@ class TestableConfigurations { : .instant("Unable to find application named 'Sublime Merge'", .stdErr), "/usr/bin/open -Ra \"iTerm\"" : .instant("Unable to find application named 'iTerm'", .stdErr), + ], + commandOutput: [ + "/opt/homebrew/bin/php-config --version": "8.1.10", + "/opt/homebrew/bin/php -r echo ini_get('memory_limit');": "512M", + "/opt/homebrew/bin/php -r echo ini_get('upload_max_filesize');": "512M", + "/opt/homebrew/bin/php -r echo ini_get('post_max_size');": "512M", + "/opt/homebrew/bin/php -r echo php_ini_scanned_files();" + : """ + /opt/homebrew/etc/php/8.1/conf.d/error_log.ini, + /opt/homebrew/etc/php/8.1/conf.d/ext-opcache.ini, + /opt/homebrew/etc/php/8.1/conf.d/php-memory-limits.ini, + /opt/homebrew/etc/php/8.1/conf.d/xdebug.ini + """ ] ) } diff --git a/phpmon/Domain/Watcher/App+ConfigWatch.swift b/phpmon/Domain/Watcher/App+ConfigWatch.swift index bde582f..22b3e32 100644 --- a/phpmon/Domain/Watcher/App+ConfigWatch.swift +++ b/phpmon/Domain/Watcher/App+ConfigWatch.swift @@ -28,6 +28,11 @@ extension App { } func handlePhpConfigWatcher(forceReload: Bool = false) { + if ActiveFileSystem.shared is TestableFileSystem { + Log.warn("FS watcher is disabled when using testable filesystem.") + return + } + let url = URL(fileURLWithPath: "\(Paths.etcPath)/php/\(PhpEnv.phpInstall.version.short)") // Check whether the watcher exists and schedule on the main thread