From 3267dc8addc6af4882e00ddea4e8df24dbd563bb Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Wed, 5 Oct 2022 00:38:17 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Use=20new=20`Shell.pipe`?= =?UTF-8?q?=20to=20replace=20legacy=20shell?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 14 +- phpmon/Common/Core/Paths.swift | 8 +- phpmon/Common/PHP/PHP Version/PhpEnv.swift | 14 +- phpmon/Domain/App/EnvironmentManager.swift | 4 +- phpmon/Domain/App/Startup.swift | 5 +- .../Homebrew/HomebrewDiagnostics.swift | 24 +- phpmon/Domain/Integrations/Valet/Valet.swift | 6 +- phpmon/Domain/Menu/MainMenu+Switcher.swift | 8 +- phpmon/Next/Testables.swift | 219 +++++++++++++++--- 9 files changed, 243 insertions(+), 59 deletions(-) diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 936ebe3..9eed9bf 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -59,7 +59,6 @@ C40C7F2927721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */; }; C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2F27722E8D00DDDCDC /* Logger.swift */; }; C40C7F3127722E8D00DDDCDC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C7F2F27722E8D00DDDCDC /* Logger.swift */; }; - C40F505528ECA64E004AD45B /* Testables.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40F505428ECA64E004AD45B /* Testables.swift */; }; C40F505628ECA64E004AD45B /* Testables.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40F505428ECA64E004AD45B /* Testables.swift */; }; C40FE737282ABA4F00A302C2 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE736282ABA4F00A302C2 /* AppVersion.swift */; }; C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE736282ABA4F00A302C2 /* AppVersion.swift */; }; @@ -213,6 +212,8 @@ C4ACA38F25C754C100060C66 /* PhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4ACA38E25C754C100060C66 /* PhpExtension.swift */; }; C4AD38B228ECD9D300FA8D83 /* TestableFilesystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AD38B128ECD9D300FA8D83 /* TestableFilesystem.swift */; }; C4AD38B328ECD9D300FA8D83 /* TestableFilesystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AD38B128ECD9D300FA8D83 /* TestableFilesystem.swift */; }; + C4AD38B528ECE2DB00FA8D83 /* brew-formula.json in Resources */ = {isa = PBXBuildFile; fileRef = C43A8A1F25D9D1D700591B77 /* brew-formula.json */; }; + C4AD38B628ECE56D00FA8D83 /* Testables.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40F505428ECA64E004AD45B /* Testables.swift */; }; C4AF9F72275445FF00D44ED0 /* valet-config.json in Resources */ = {isa = PBXBuildFile; fileRef = C4AF9F70275445FF00D44ED0 /* valet-config.json */; }; C4AF9F78275447F100D44ED0 /* ValetConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F76275447F100D44ED0 /* ValetConfigurationTest.swift */; }; C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AF9F792754499000D44ED0 /* Valet.swift */; }; @@ -711,6 +712,7 @@ C41C1B3522B0097F00E7CF16 /* phpmon */ = { isa = PBXGroup; children = ( + C4AD38B428ECE1E100FA8D83 /* Tests */, C46EBC3F28DB9550007ACC74 /* Next */, C4B5853A2770FE2500DA4FBE /* Common */, C41E181722CB61EB0072CF09 /* Domain */, @@ -943,6 +945,13 @@ path = "PHP Version"; sourceTree = ""; }; + C4AD38B428ECE1E100FA8D83 /* Tests */ = { + isa = PBXGroup; + children = ( + ); + path = Tests; + sourceTree = ""; + }; C4AF9F6A275445C900D44ED0 /* Valet */ = { isa = PBXGroup; children = ( @@ -1313,6 +1322,7 @@ 54FCFD26276C883F004CE748 /* SelectPreferenceView.xib in Resources */, C473319F2470923A009A0597 /* Localizable.strings in Resources */, C4068CA427B0780A00544CD5 /* CheckboxPreferenceView.xib in Resources */, + C4AD38B528ECE2DB00FA8D83 /* brew-formula.json in Resources */, 54FCFD2D276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */, C405A4D024B9B9140062FAFA /* InternetAccessPolicy.strings in Resources */, ); @@ -1453,6 +1463,7 @@ C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */, C45E76142854A65300B4FE0C /* ServicesManager.swift in Sources */, C46EBC4728DB9644007ACC74 /* SystemShell.swift in Sources */, + C4AD38B628ECE56D00FA8D83 /* Testables.swift in Sources */, C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */, C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */, C4C8E81B276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */, @@ -1497,7 +1508,6 @@ C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */, C40508AF28ADA23D008FAC1F /* NoDomainResultsView.swift in Sources */, C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */, - C40F505528ECA64E004AD45B /* Testables.swift in Sources */, C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */, C42E3BF428A9BF5100AFECFC /* LegacyShell+PATH.swift in Sources */, C42337A3281F19F000459A48 /* Xdebug.swift in Sources */, diff --git a/phpmon/Common/Core/Paths.swift b/phpmon/Common/Core/Paths.swift index a4a5233..ac34932 100644 --- a/phpmon/Common/Core/Paths.swift +++ b/phpmon/Common/Core/Paths.swift @@ -17,11 +17,15 @@ public class Paths { internal var baseDir: Paths.HomebrewDir - private var userName: String + private var userName: String! = nil init() { baseDir = App.architecture != "x86_64" ? .opt : .usr - userName = String(LegacyShell.pipe("id -un").split(separator: "\n")[0]) + + Task { + let output = await Shell.pipe("id -un").out + userName = String(output.split(separator: "\n")[0]) + } } public func detectBinaryPaths() { diff --git a/phpmon/Common/PHP/PHP Version/PhpEnv.swift b/phpmon/Common/PHP/PHP Version/PhpEnv.swift index fcbe844..1a00fef 100644 --- a/phpmon/Common/PHP/PHP Version/PhpEnv.swift +++ b/phpmon/Common/PHP/PHP Version/PhpEnv.swift @@ -15,14 +15,16 @@ class PhpEnv { init() { self.currentInstall = ActivePhpInstallation() - let brewPhpAlias = LegacyShell.pipe("\(Paths.brew) info php --json") + Task { + let brewPhpAlias = await Shell.pipe("\(Paths.brew) info php --json").out - self.homebrewPackage = try! JSONDecoder().decode( - [HomebrewPackage].self, - from: brewPhpAlias.data(using: .utf8)! - ).first! + self.homebrewPackage = try! JSONDecoder().decode( + [HomebrewPackage].self, + from: brewPhpAlias.data(using: .utf8)! + ).first! - Log.info("When on your system, the `php` formula means version \(homebrewPackage.version)!") + Log.info("When on your system, the `php` formula means version \(homebrewPackage.version)!") + } } // MARK: - Properties diff --git a/phpmon/Domain/App/EnvironmentManager.swift b/phpmon/Domain/App/EnvironmentManager.swift index b7f05cd..effcc9d 100644 --- a/phpmon/Domain/App/EnvironmentManager.swift +++ b/phpmon/Domain/App/EnvironmentManager.swift @@ -12,8 +12,8 @@ public class EnvironmentManager { var values: [EnvironmentProperty: Bool] = [:] public func process() async { - self.values[.hasValetInstalled] = !{ - let output = valet("--version", sudo: false) + self.values[.hasValetInstalled] = await !{ + let output = await Shell.pipe("valet --version").out // Failure condition #1: does not contain Laravel Valet if !output.contains("Laravel Valet") { diff --git a/phpmon/Domain/App/Startup.swift b/phpmon/Domain/App/Startup.swift index 82e306c..5aaf2c7 100644 --- a/phpmon/Domain/App/Startup.swift +++ b/phpmon/Domain/App/Startup.swift @@ -160,7 +160,10 @@ class Startup { // Verify if the Homebrew services are running (as root). // ================================================================================= EnvironmentCheck( - command: { return HomebrewDiagnostics.cannotLoadService() }, + command: { + await HomebrewDiagnostics.loadInstalledTaps() + return await HomebrewDiagnostics.cannotLoadService("nginx") + }, name: "`sudo \(Paths.brew) services info` JSON loaded", titleText: "startup.errors.services_json_error.title".localized, subtitleText: "startup.errors.services_json_error.subtitle".localized, diff --git a/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift b/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift index b77fc92..e9dc210 100644 --- a/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift +++ b/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift @@ -9,18 +9,23 @@ import Foundation class HomebrewDiagnostics { - /** Determines the Homebrew taps the user has installed. */ - public static var installedTaps: [String] = { - return LegacyShell + public static var installedTaps: [String] = [] + + /** + Load which taps are installed. + */ + public static func loadInstalledTaps() async { + installedTaps = await Shell .pipe("\(Paths.brew) tap") + .out .split(separator: "\n") .map { string in return String(string) } - }() + } /** Determines whether the PHP Monitor Cask is installed. @@ -131,13 +136,14 @@ class HomebrewDiagnostics { In order to see if we support the --json syntax, we'll query nginx. If the JSON response cannot be parsed, Homebrew is probably out of date. */ - public static func cannotLoadService(_ name: String = "nginx") -> Bool { + public static func cannotLoadService(_ name: String) async -> Bool { + let nginxJson = await Shell + .pipe("sudo \(Paths.brew) services info \(name) --json") + .out + let serviceInfo = try? JSONDecoder().decode( [HomebrewService].self, - from: LegacyShell.pipe( - "sudo \(Paths.brew) services info \(name) --json", - requiresPath: true - ).data(using: .utf8)! + from: nginxJson.data(using: .utf8)! ) return serviceInfo == nil diff --git a/phpmon/Domain/Integrations/Valet/Valet.swift b/phpmon/Domain/Integrations/Valet/Valet.swift index 6aaafea..f023662 100644 --- a/phpmon/Domain/Integrations/Valet/Valet.swift +++ b/phpmon/Domain/Integrations/Valet/Valet.swift @@ -183,9 +183,9 @@ class Valet { } } - public func hasPlatformIssues() -> Bool { - return valet("--version", sudo: false) - .contains("Composer detected issues in your platform") + public func hasPlatformIssues() async -> Bool { + return await Shell.pipe("valet --version") + .out.contains("Composer detected issues in your platform") } /** diff --git a/phpmon/Domain/Menu/MainMenu+Switcher.swift b/phpmon/Domain/Menu/MainMenu+Switcher.swift index 66c61d2..fc55377 100644 --- a/phpmon/Domain/Menu/MainMenu+Switcher.swift +++ b/phpmon/Domain/Menu/MainMenu+Switcher.swift @@ -53,9 +53,11 @@ extension MainMenu { } @MainActor private func checkForPlatformIssues() { - if Valet.shared.hasPlatformIssues() { - Log.info("Composer platform issue(s) detected.") - self.suggestFixMyComposer() + Task { + if await Valet.shared.hasPlatformIssues() { + Log.info("Composer platform issue(s) detected.") + self.suggestFixMyComposer() + } } } diff --git a/phpmon/Next/Testables.swift b/phpmon/Next/Testables.swift index 921f0aa..9795cce 100644 --- a/phpmon/Next/Testables.swift +++ b/phpmon/Next/Testables.swift @@ -8,7 +8,6 @@ import Foundation -// struct TestableConfiguration { let architecture: String let filesystem: [String: FakeFile] @@ -51,38 +50,11 @@ class Testables { "which node" : .instant("/opt/homebrew/bin/node"), "php -v" - : .instant(""" - PHP 8.1.10 (cli) (built: Sep 3 2022 12:09:27) (NTS) - Copyright (c) The PHP Group - Zend Engine v4.1.10, Copyright (c) Zend Technologies - with Zend OPcache v8.1.10, Copyright (c), by Zend Technologies - """), + : .instant(ShellStrings.phpVersion), "ls /opt/homebrew/opt | grep php" : .instant("php"), "sudo /opt/homebrew/bin/brew services info nginx --json" - : .delayed(0.2, """ - [ - { - "name": "nginx", - "service_name": "homebrew.mxcl.nginx", - "running": true, - "loaded": true, - "schedulable": false, - "pid": 133, - "exit_code": 0, - "user": "root", - "status": "started", - "file": "/Library/LaunchDaemons/homebrew.mxcl.nginx.plist", - "command": "/opt/homebrew/opt/nginx/bin/nginx -g daemon off;", - "working_dir": "/opt/homebrew", - "root_dir": null, - "log_path": null, - "error_log_path": null, - "interval": null, - "cron": null - } - ] - """), + : .delayed(0.2, ShellStrings.nginxJson), "cat /private/etc/sudoers.d/brew" : .instant(""" Cmnd_Alias BREW = /opt/homebrew/bin/brew * @@ -94,8 +66,193 @@ class Testables { %admin ALL=(root) NOPASSWD:SETENV: VALET """), "valet --version" - : .instant("Laravel Valet 3.1.11") + : .instant("Laravel Valet 3.1.11"), + "/opt/homebrew/bin/brew tap" + : .instant(""" + homebrew/cask + homebrew/core + homebrew/services + nicoverbruggen/cask + shivammathur/php + """), + "/opt/homebrew/bin/brew info php --json" + : .instant(ShellStrings.brewJson) ] ) } } + +struct ShellStrings { + + static let phpVersion = """ + PHP 8.1.10 (cli) (built: Sep 3 2022 12:09:27) (NTS) + Copyright (c) The PHP Group + Zend Engine v4.1.10, Copyright (c) Zend Technologies + with Zend OPcache v8.1.10, Copyright (c), by Zend Technologies + """ + + static let nginxJson = """ + [ + { + "name": "nginx", + "service_name": "homebrew.mxcl.nginx", + "running": true, + "loaded": true, + "schedulable": false, + "pid": 133, + "exit_code": 0, + "user": "root", + "status": "started", + "file": "/Library/LaunchDaemons/homebrew.mxcl.nginx.plist", + "command": "/opt/homebrew/opt/nginx/bin/nginx -g daemon off;", + "working_dir": "/opt/homebrew", + "root_dir": null, + "log_path": null, + "error_log_path": null, + "interval": null, + "cron": null + } + ] + """ + + static let brewJson = """ + [ + { + "name":"php", + "full_name":"php", + "tap":"homebrew/core", + "oldname":null, + "aliases":[ + "php@8.0" + ], + "versioned_formulae":[ + "php@7.4", + "php@7.3", + "php@7.2" + ], + "desc":"General-purpose scripting language", + "license":"PHP-3.01", + "homepage":"https://www.php.net/", + "versions":{ + "stable":"8.0.2", + "head":"HEAD", + "bottle":true + }, + "urls":{ + "stable":{ + "url":"https://www.php.net/distributions/php-8.0.2.tar.xz", + "tag":null, + "revision":null + } + }, + "revision":0, + "version_scheme":0, + "bottle":{ + "stable":{ + "rebuild":0, + "cellar":"/opt/homebrew/Cellar", + "prefix":"/opt/homebrew", + "root_url":"https://homebrew.bintray.com/bottles", + "files":{ + "arm64_big_sur":{ + "url":"https://homebrew.bintray.com/bottles/php-8.0.2.arm64_big_sur.bottle.tar.gz", + "sha256":"cbefa1db73d08b9af4593a44512b8d727e43033ee8517736bae5f16315501b12" + }, + "big_sur":{ + "url":"https://homebrew.bintray.com/bottles/php-8.0.2.big_sur.bottle.tar.gz", + "sha256":"6857142e12254b15da4e74c2986dd24faca57dac8d467b04621db349e277dd63" + }, + "catalina":{ + "url":"https://homebrew.bintray.com/bottles/php-8.0.2.catalina.bottle.tar.gz", + "sha256":"b651611134c18f93fdf121a4277b51b197a896a19ccb8020289b4e19e0638349" + }, + "mojave":{ + "url":"https://homebrew.bintray.com/bottles/php-8.0.2.mojave.bottle.tar.gz", + "sha256":"9583a51fcc6f804aadbb14e18f770d4fb4973deaed6ddc4770342e62974ffbca" + } + } + } + }, + "keg_only":false, + "bottle_disabled":false, + "options":[ + + ], + "build_dependencies":[ + "httpd", + "pkg-config" + ], + "dependencies":[ + "apr", + "apr-util", + "argon2", + "aspell", + "autoconf", + "curl", + "freetds", + "gd", + "gettext", + "glib", + "gmp", + "icu4c", + "krb5", + "libffi", + "libpq", + "libsodium", + "libzip", + "oniguruma", + "openldap", + "openssl@1.1", + "pcre2", + "sqlite", + "tidy-html5", + "unixodbc" + ], + "recommended_dependencies":[ + + ], + "optional_dependencies":[ + + ], + "uses_from_macos":[ + { + "xz":"build" + }, + "bzip2", + "libedit", + "libxml2", + "libxslt", + "zlib" + ], + "requirements":[ + + ], + "conflicts_with":[ + + ], + "installed":[ + { + "version": "8.1.10_1", + "used_options": [ + + ], + "built_as_bottle": true, + "poured_from_bottle": true, + "runtime_dependencies": [], + "installed_as_dependency": false, + "installed_on_request": true + } + ], + "linked_keg":"8.0.2", + "pinned":false, + "outdated":false, + "deprecated":false, + "deprecation_date":null, + "deprecation_reason":null, + "disabled":false, + "disable_date":null, + "disable_reason":null + } + ] + """ +}