From 2bd5b8f79e544ce79d74955c3ab140303ac1cf11 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Tue, 14 Mar 2023 22:10:48 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Ensure=20Valet=20configuration=20fi?= =?UTF-8?q?les=20exist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 10 ++ .../PHP/Switcher/InternalSwitcher+Valet.swift | 134 ++++++++++++++++++ .../PHP/Switcher/InternalSwitcher.swift | 37 +---- .../Homebrew/HomebrewDiagnostics.swift | 26 ++-- phpmon/Domain/Menu/MainMenu+Startup.swift | 8 +- 5 files changed, 161 insertions(+), 54 deletions(-) create mode 100644 phpmon/Common/PHP/Switcher/InternalSwitcher+Valet.swift diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 48cf32b..2ac6517 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -650,6 +650,10 @@ C4D3661B291173EA006BD146 /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36619291173EA006BD146 /* DictionaryExtension.swift */; }; C4D3661C291173EA006BD146 /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36619291173EA006BD146 /* DictionaryExtension.swift */; }; C4D3661D291173EA006BD146 /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D36619291173EA006BD146 /* DictionaryExtension.swift */; }; + C4D4CB3729C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D4CB3629C109CF00DB9F93 /* InternalSwitcher+Valet.swift */; }; + C4D4CB3829C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D4CB3629C109CF00DB9F93 /* InternalSwitcher+Valet.swift */; }; + C4D4CB3929C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D4CB3629C109CF00DB9F93 /* InternalSwitcher+Valet.swift */; }; + C4D4CB3A29C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D4CB3629C109CF00DB9F93 /* InternalSwitcher+Valet.swift */; }; C4D5CFCA27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; }; C4D5CFCB27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; }; C4D8016622B1584700C6DA1B /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; }; @@ -972,6 +976,7 @@ C4D3660F291140BE006BD146 /* TestableFileSystemTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableFileSystemTest.swift; sourceTree = ""; }; C4D36614291160A1006BD146 /* WIP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WIP.swift; sourceTree = ""; }; C4D36619291173EA006BD146 /* DictionaryExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryExtension.swift; sourceTree = ""; }; + C4D4CB3629C109CF00DB9F93 /* InternalSwitcher+Valet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InternalSwitcher+Valet.swift"; sourceTree = ""; }; C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfigurationFile.swift; sourceTree = ""; }; C4D8016522B1584700C6DA1B /* Startup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Startup.swift; sourceTree = ""; }; C4D89BC52783C99400A02B68 /* ComposerJson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerJson.swift; sourceTree = ""; }; @@ -1771,6 +1776,7 @@ children = ( C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */, C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */, + C4D4CB3629C109CF00DB9F93 /* InternalSwitcher+Valet.swift */, ); path = Switcher; sourceTree = ""; @@ -2256,6 +2262,7 @@ 03E36FE728D9219000636F7F /* ActiveShell.swift in Sources */, C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */, C45E76142854A65300B4FE0C /* ServicesManager.swift in Sources */, + C4D4CB3729C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */, C46EBC4728DB9644007ACC74 /* RealShell.swift in Sources */, C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */, C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */, @@ -2361,6 +2368,7 @@ C471E84828F9BB650021E251 /* EnvironmentCheck.swift in Sources */, C471E84A28F9BB650021E251 /* AppVersion.swift in Sources */, C471E84B28F9BB650021E251 /* ServicesManager.swift in Sources */, + C4D4CB3929C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */, C471E84C28F9BB650021E251 /* EnvironmentManager.swift in Sources */, C471E84D28F9BB650021E251 /* ActivePhpInstallation+Checks.swift in Sources */, C471E84E28F9BB650021E251 /* MainMenu.swift in Sources */, @@ -2571,6 +2579,7 @@ C471E8C928F9BB8F0021E251 /* WarningsWindowController.swift in Sources */, C41ADCEB2970CCC700120423 /* FSNotifier.swift in Sources */, C471E8CA28F9BB8F0021E251 /* OnboardingWindowController.swift in Sources */, + C4D4CB3A29C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */, C471E8CB28F9BB8F0021E251 /* PreferencesWindowController.swift in Sources */, C471E8CC28F9BB8F0021E251 /* PreferencesWindowController+Hotkey.swift in Sources */, C471E8CD28F9BB8F0021E251 /* PrefsVC.swift in Sources */, @@ -2853,6 +2862,7 @@ C41C02AB27E61CB3009F26CB /* FakeValetSite.swift in Sources */, C4F780C925D80B75000DBC97 /* StringExtension.swift in Sources */, C4D9F24C280B69E100DCD39A /* AddProxyVC.swift in Sources */, + C4D4CB3829C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */, C4B5853F2770FE3900DA4FBE /* Paths.swift in Sources */, C481F79A26164A7C004FBCFF /* Preferences.swift in Sources */, C4A6957728D23EE300A14CF8 /* EnvironmentManager.swift in Sources */, diff --git a/phpmon/Common/PHP/Switcher/InternalSwitcher+Valet.swift b/phpmon/Common/PHP/Switcher/InternalSwitcher+Valet.swift new file mode 100644 index 0000000..83de877 --- /dev/null +++ b/phpmon/Common/PHP/Switcher/InternalSwitcher+Valet.swift @@ -0,0 +1,134 @@ +// +// InternalSwitcher+Valet.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 14/03/2023. +// Copyright © 2023 Nico Verbruggen. All rights reserved. +// + +import Foundation + +extension InternalSwitcher { + + typealias FixApplied = Bool + + public func ensureValetConfigurationIsValidForPhpVersion(_ version: String) async -> FixApplied { + // Early exit if Valet is not installed + if !Valet.installed { + assertionFailure("Cannot ensure that Valet configuration is valid if Valet is not installed.") + return false + } + + let corrections = [ + await self.disableDefaultPhpFpmPool(version), + await self.ensureConfigurationFilesExist(version) + ] + + return corrections.contains(true) + } + + // MARK: - PHP FPM pool + + public func disableDefaultPhpFpmPool(_ version: String) async -> FixApplied { + let pool = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf" + + if FileSystem.fileExists(pool) { + Log.info("A default `www.conf` file was found in the php-fpm.d directory for PHP \(version).") + let existing = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf" + let new = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf.disabled-by-phpmon" + do { + if FileSystem.fileExists(new) { + Log.info("A moved `www.conf.disabled-by-phpmon` file was found for PHP \(version), " + + "cleaning up so the newer `www.conf` can be moved again.") + try FileSystem.remove(new) + } + try FileSystem.move(from: existing, to: new) + Log.info("Success: A default `www.conf` file was disabled for PHP \(version).") + return true + } catch { + Log.err(error) + return false + } + } + + return false + } + + func getExpectedConfigurationFiles(for version: String) -> [ExpectedConfigurationFile] { + return [ + ExpectedConfigurationFile( + destination: "/php-fpm.d/valet-fpm.conf", + source: "/cli/stubs/etc-phpfpm-valet.conf", + replacements: [ + "VALET_USER": Paths.whoami, + "VALET_HOME_PATH": "~/.config/valet".replacingTildeWithHomeDirectory, + "valet.sock": "valet\(version.replacingOccurrences(of: ".", with: "")).sock" + ], + applies: { Valet.shared.version!.major > 2 } + ), + ExpectedConfigurationFile( + destination: "/conf.d/error_log.ini", + source: "/cli/stubs/etc-phpfpm-error_log.ini", + replacements: [ + "VALET_USER": Paths.whoami, + "VALET_HOME_PATH": "~/.config/valet".replacingTildeWithHomeDirectory + ], + applies: { return true } + ), + ExpectedConfigurationFile( + destination: "/conf.d/php-memory-limits.ini", + source: "/cli/stubs/php-memory-limits.ini", + replacements: [:], + applies: { return true } + ) + ] + } + + func ensureConfigurationFilesExist(_ version: String) async -> FixApplied { + let files = self.getExpectedConfigurationFiles(for: version) + + // For each of the files, attempt to fix anything that is wrong + let outcomes = files.map { file in + let configFileExists = FileSystem.fileExists("\(Paths.etcPath)/php/\(version)/" + file.destination) + + if configFileExists { + return false + } + + Log.info("Config file `\(file.destination)` does not exist, will attempt to automatically fix!") + + if !file.applies() { + return false + } + + do { + var contents = try FileSystem.getStringFromFile("~/.composer/vendor/laravel/valet" + file.source) + + for (original, replacement) in file.replacements { + contents = contents.replacingOccurrences(of: original, with: replacement) + } + + try FileSystem.writeAtomicallyToFile( + "\(Paths.etcPath)/php/\(version)" + file.destination, + content: contents + ) + } catch { + Log.err("Automatically fixing \(file.destination) did not work.") + return false + } + + return true + } + + // If any fixes were applied, return true + return outcomes.contains(true) + } + +} + +public struct ExpectedConfigurationFile { + let destination: String + let source: String + let replacements: [String: String] + let applies: () -> Bool +} diff --git a/phpmon/Common/PHP/Switcher/InternalSwitcher.swift b/phpmon/Common/PHP/Switcher/InternalSwitcher.swift index e1cc30f..f09d057 100644 --- a/phpmon/Common/PHP/Switcher/InternalSwitcher.swift +++ b/phpmon/Common/PHP/Switcher/InternalSwitcher.swift @@ -27,7 +27,6 @@ class InternalSwitcher: PhpSwitcher { await withTaskGroup(of: String.self, body: { group in for available in PhpEnv.shared.availablePhpVersions { group.addTask { - await self.disableDefaultPhpFpmPool(available) await self.unlinkAndStopPhpVersion(available) return available } @@ -42,6 +41,11 @@ class InternalSwitcher: PhpSwitcher { Log.info("Linking the new version \(version)!") for formula in versions { + if Valet.installed { + Log.info("Ensuring that the Valet configuration is valid...") + _ = await self.ensureValetConfigurationIsValidForPhpVersion(formula) + } + Log.info("Will start PHP \(version)... (primary: \(version == formula))") await self.linkAndStartPhpVersion(formula, primary: (version == formula)) } @@ -71,37 +75,6 @@ class InternalSwitcher: PhpSwitcher { return versions } - func requiresDisablingOfDefaultPhpFpmPool(_ version: String) -> Bool { - let pool = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf" - return FileSystem.fileExists(pool) - } - - func disableDefaultPhpFpmPool(_ version: String) async { - if Valet.installed { - Log.info("Skipping adjustment of php-fpm.d pools, because Valet is disabled or not installed.") - Log.info("This behaviour may not be desirable with this system configuration.") - return - } - - let pool = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf" - if FileSystem.fileExists(pool) { - Log.info("A default `www.conf` file was found in the php-fpm.d directory for PHP \(version).") - let existing = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf" - let new = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf.disabled-by-phpmon" - do { - if FileSystem.fileExists(new) { - Log.info("A moved `www.conf.disabled-by-phpmon` file was found for PHP \(version), " - + "cleaning up so the newer `www.conf` can be moved again.") - try FileSystem.remove(new) - } - try FileSystem.move(from: existing, to: new) - Log.info("Success: A default `www.conf` file was disabled for PHP \(version).") - } catch { - Log.err(error) - } - } - } - func unlinkAndStopPhpVersion(_ version: String) async { let formula = (version == PhpEnv.brewPhpAlias) ? "php" : "php@\(version)" await brew("unlink \(formula)") diff --git a/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift b/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift index a7b8554..3a31a1c 100644 --- a/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift +++ b/phpmon/Domain/Integrations/Homebrew/HomebrewDiagnostics.swift @@ -63,11 +63,11 @@ class HomebrewDiagnostics { It is possible to upgrade PHP, but forget running `valet install`. This results in a scenario where a rogue www.conf file exists. */ - public static func checkForPhpFpmPoolConflicts() { - Log.info("Checking for PHP-FPM pool conflicts...") + public static func checkForValetMisconfiguration() async { + Log.info("Checking for PHP-FPM issues with Valet...") guard let install = PhpEnv.phpInstall else { - Log.info("Will skip check for conflicts if no PHP version is linked.") + Log.info("Will skip check for issues if no PHP version is linked.") return } @@ -76,22 +76,12 @@ class HomebrewDiagnostics { // Versions to be handled let switcher = InternalSwitcher() - var versions = switcher.getVersionsToBeHandled(primary) - versions = versions.filter { version in - return switcher.requiresDisablingOfDefaultPhpFpmPool(version) - } - - if versions.isEmpty { - Log.info("No PHP-FPM pools need to be fixed. All OK.") - } - - versions.forEach { version in - Task { // Fix each pool concurrently (but perform the tasks sequentially) - await switcher.disableDefaultPhpFpmPool(version) - await switcher.unlinkAndStopPhpVersion(version) - await switcher.linkAndStartPhpVersion(version, primary: version == primary) - } + for version in switcher.getVersionsToBeHandled(primary) + where await switcher.ensureValetConfigurationIsValidForPhpVersion(version) { + Log.info("One or more fixes were applied for PHP \(version)!") + await switcher.unlinkAndStopPhpVersion(version) + await switcher.linkAndStartPhpVersion(version, primary: version == primary) } } diff --git a/phpmon/Domain/Menu/MainMenu+Startup.swift b/phpmon/Domain/Menu/MainMenu+Startup.swift index f0d7df5..b82f28b 100644 --- a/phpmon/Domain/Menu/MainMenu+Startup.swift +++ b/phpmon/Domain/Menu/MainMenu+Startup.swift @@ -91,11 +91,11 @@ extension MainMenu { // Preload all sites await Valet.shared.startPreloadingSites() - // Check if PHP-FPM is broken - await Valet.shared.notifyAboutBrokenPhpFpm() - // After preloading sites, check for PHP-FPM pool conflicts - HomebrewDiagnostics.checkForPhpFpmPoolConflicts() + await HomebrewDiagnostics.checkForValetMisconfiguration() + + // Check if PHP-FPM is broken (should be fixed automatically if phpmon >= 6.0) + await Valet.shared.notifyAboutBrokenPhpFpm() // A non-default TLD is not officially supported since Valet 3.2.x Valet.notifyAboutUnsupportedTLD()