From 7e78026d0685145c1fa8a3277de20bf52be8a1e7 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Tue, 12 Sep 2023 19:26:10 +0200 Subject: [PATCH 01/12] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20WIP:=20PHP=20Conf?= =?UTF-8?q?ig=20Editor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Has UI height rendering issues (w/ SwiftUI) - Needs debounce on UI elements - Cannot currently persist modified settings - Cannot display On/Off settings - Cannot display regular text settings --- PHP Monitor.xcodeproj/project.pbxproj | 28 +++++++----- phpmon/Common/PHP/PhpConfigurationFile.swift | 3 +- phpmon/Domain/App/App.swift | 5 ++- phpmon/Domain/Menu/MainMenu.swift | 4 ++ phpmon/Domain/Menu/StatusMenu+Items.swift | 3 ++ .../Data/BytePhpPreference.swift | 7 +++ .../Data/PhpPreference.swift | 8 ++++ .../PHP Config Editor/UI/ByteLimitView.swift | 3 +- .../UI/ConfigManagerView.swift | 4 +- .../UI/ConfigManagerWindowController.swift | 45 +++++++++++++++++++ phpmon/en.lproj/Localizable.strings | 1 + 11 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 phpmon/Modules/PHP Config Editor/UI/ConfigManagerWindowController.swift diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 377d70d..49c32df 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -132,6 +132,7 @@ C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1527DFDE7900862737 /* nginx-site.test */; }; C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */; }; C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */; }; + C42E3F772AB0D2880096DFC2 /* ConfigManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */; }; C42F26732805B4B400938AC7 /* ValetListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* ValetListable.swift */; }; C42F26742805B4B400938AC7 /* ValetListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* ValetListable.swift */; }; C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */; }; @@ -929,6 +930,7 @@ C42CFB1527DFDE7900862737 /* nginx-site.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site.test"; sourceTree = ""; }; C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site-isolated.test"; sourceTree = ""; }; C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfigurationTest.swift; sourceTree = ""; }; + C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigManagerWindowController.swift; sourceTree = ""; }; C42F26722805B4B400938AC7 /* ValetListable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetListable.swift; sourceTree = ""; }; C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-secure-proxy.test"; sourceTree = ""; }; C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Notifications.swift"; sourceTree = ""; }; @@ -1499,6 +1501,7 @@ children = ( C44DFA7B2A67043000B98ED5 /* ConfigManagerView.swift */, C4D5857B2A7038DB00DDBB63 /* ByteLimitView.swift */, + C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */, ); path = UI; sourceTree = ""; @@ -2568,6 +2571,7 @@ C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */, C464ADAC275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */, C4CB6E65292C362C002E9027 /* Homebrew.swift in Sources */, + C42E3F772AB0D2880096DFC2 /* ConfigManagerWindowController.swift in Sources */, C464ADB2275A87CA003FCD53 /* DomainListCellProtocol.swift in Sources */, C4EE188422D3386B00E126E5 /* Constants.swift in Sources */, C493084A279F331F009C240B /* AddSiteVC.swift in Sources */, @@ -3488,7 +3492,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1320; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3501,7 +3505,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.4; - MARKETING_VERSION = 6.1; + MARKETING_VERSION = 6.2; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -3519,7 +3523,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1320; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3532,7 +3536,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.4; - MARKETING_VERSION = 6.1; + MARKETING_VERSION = 6.2; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -3759,7 +3763,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1320; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3772,7 +3776,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.4; - MARKETING_VERSION = 6.1; + MARKETING_VERSION = 6.2; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev; PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_NAME = "$(TARGET_NAME) DEV"; @@ -3875,7 +3879,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1320; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3888,7 +3892,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.4; - MARKETING_VERSION = 6.1; + MARKETING_VERSION = 6.2; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev; PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_NAME = "$(TARGET_NAME) DEV"; @@ -3991,7 +3995,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1320; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -4004,7 +4008,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.4; - MARKETING_VERSION = 6.1; + MARKETING_VERSION = 6.2; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap; PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_NAME = "$(TARGET_NAME) EAP"; @@ -4172,7 +4176,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1320; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -4185,7 +4189,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.4; - MARKETING_VERSION = 6.1; + MARKETING_VERSION = 6.2; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap; PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_NAME = "$(TARGET_NAME) EAP"; diff --git a/phpmon/Common/PHP/PhpConfigurationFile.swift b/phpmon/Common/PHP/PhpConfigurationFile.swift index 9ce7907..42d5165 100644 --- a/phpmon/Common/PHP/PhpConfigurationFile.swift +++ b/phpmon/Common/PHP/PhpConfigurationFile.swift @@ -69,8 +69,9 @@ class PhpConfigurationFile: CreatedFromFile { return nil } - enum ReplacementErrors: Error { + public enum ReplacementErrors: Error { case missingKey + case missingFile } /** diff --git a/phpmon/Domain/App/App.swift b/phpmon/Domain/App/App.swift index f991591..3c89866 100644 --- a/phpmon/Domain/App/App.swift +++ b/phpmon/Domain/App/App.swift @@ -74,10 +74,13 @@ class App { /** The window controller of the onboarding window. */ var onboardingWindowController: OnboardingWindowController? + /** The window controller of the config manager window. */ + var phpConfigManagerWindowController: PhpConfigManagerWindowController? + /** The window controller of the warnings window. */ var phpDoctorWindowController: PhpDoctorWindowController? - /** The window controller of the warnings window. */ + /** The window controller of the PHP version manager window. */ var phpVersionManagerWindowController: PhpVersionManagerWindowController? /** List of detected (installed) applications that PHP Monitor can work with. */ diff --git a/phpmon/Domain/Menu/MainMenu.swift b/phpmon/Domain/Menu/MainMenu.swift index dcc0c09..c0288fc 100644 --- a/phpmon/Domain/Menu/MainMenu.swift +++ b/phpmon/Domain/Menu/MainMenu.swift @@ -206,6 +206,10 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate PhpDoctorWindowController.show() } + @objc func openConfigGUI() { + PhpConfigManagerWindowController.show() + } + @objc func openDomainList() { DomainListVC.show() } diff --git a/phpmon/Domain/Menu/StatusMenu+Items.swift b/phpmon/Domain/Menu/StatusMenu+Items.swift index fd9ca10..6b6642e 100644 --- a/phpmon/Domain/Menu/StatusMenu+Items.swift +++ b/phpmon/Domain/Menu/StatusMenu+Items.swift @@ -152,6 +152,9 @@ extension StatusMenu { NSMenuItem(title: "mi_php_version_manager".localized, action: #selector(MainMenu.openPhpVersionManager), keyEquivalent: "m"), + NSMenuItem(title: "mi_php_config_manager".localized, + action: #selector(MainMenu.openConfigGUI), + keyEquivalent: "g"), NSMenuItem(title: "mi_php_config".localized, action: #selector(MainMenu.openActiveConfigFolder), keyEquivalent: "c"), diff --git a/phpmon/Modules/PHP Config Editor/Data/BytePhpPreference.swift b/phpmon/Modules/PHP Config Editor/Data/BytePhpPreference.swift index 5a4adc3..6509737 100644 --- a/phpmon/Modules/PHP Config Editor/Data/BytePhpPreference.swift +++ b/phpmon/Modules/PHP Config Editor/Data/BytePhpPreference.swift @@ -53,6 +53,13 @@ class BytePhpPreference: PhpPreference { private func updatedFieldValue() { internalValue = "\(value)\(unit.rawValue)" + + do { + try PhpPreference.persistToIniFile(key: self.key, value: self.internalValue) + Log.info("The preference \(key) was updated to: \(value)") + } catch { + Log.info("The preference \(key) could not be updated") + } } public static func readFrom(internalValue: String) -> (UnitOption, Int)? { diff --git a/phpmon/Modules/PHP Config Editor/Data/PhpPreference.swift b/phpmon/Modules/PHP Config Editor/Data/PhpPreference.swift index b49dea0..a6d8fd3 100644 --- a/phpmon/Modules/PHP Config Editor/Data/PhpPreference.swift +++ b/phpmon/Modules/PHP Config Editor/Data/PhpPreference.swift @@ -15,6 +15,14 @@ class PhpPreference { init(key: String) { self.key = key } + + internal static func persistToIniFile(key: String, value: String) throws { + if let file = PhpEnvironments.shared.getConfigFile(forKey: key) { + try file.replace(key: key, value: value) + } + + throw PhpConfigurationFile.ReplacementErrors.missingFile + } } class BoolPhpPreference: PhpPreference { diff --git a/phpmon/Modules/PHP Config Editor/UI/ByteLimitView.swift b/phpmon/Modules/PHP Config Editor/UI/ByteLimitView.swift index 71cabab..c98c0d1 100644 --- a/phpmon/Modules/PHP Config Editor/UI/ByteLimitView.swift +++ b/phpmon/Modules/PHP Config Editor/UI/ByteLimitView.swift @@ -40,7 +40,7 @@ struct PreferenceContainer: View { .font(.subheadline) .fixedSize(horizontal: false, vertical: true) } - .frame(maxWidth: .infinity, alignment: .topLeading) + .frame(maxWidth: .infinity, maxHeight: 150, alignment: .topLeading) } } .padding(5) @@ -79,7 +79,6 @@ struct ByteLimitView: View { .pickerStyle(.menu) .onChange(of: unit) { newValue in self.preference.unit = newValue - print(self.preference.internalValue) } } } diff --git a/phpmon/Modules/PHP Config Editor/UI/ConfigManagerView.swift b/phpmon/Modules/PHP Config Editor/UI/ConfigManagerView.swift index dd9de19..28d72f3 100644 --- a/phpmon/Modules/PHP Config Editor/UI/ConfigManagerView.swift +++ b/phpmon/Modules/PHP Config Editor/UI/ConfigManagerView.swift @@ -13,7 +13,7 @@ struct ConfigManagerView: View { var preferences: [PhpPreference] = [ BytePhpPreference(key: "memory_limit"), BytePhpPreference(key: "post_max_size"), - BoolPhpPreference(key: "file_uploads"), + // BoolPhpPreference(key: "file_uploads"), BytePhpPreference(key: "upload_max_filesize") ] @@ -51,6 +51,7 @@ struct ConfigManagerView: View { if let preference = preference as? BytePhpPreference { ByteLimitView(preference: preference) } + /* if let preference = preference as? BoolPhpPreference { Toggle("", isOn: preference.$value) .toggleStyle(.switch) @@ -59,6 +60,7 @@ struct ConfigManagerView: View { if let preference = preference as? StringPhpPreference { TextField("Placeholder", text: preference.$value) } + */ }.frame(maxWidth: .infinity) } }.padding(10) diff --git a/phpmon/Modules/PHP Config Editor/UI/ConfigManagerWindowController.swift b/phpmon/Modules/PHP Config Editor/UI/ConfigManagerWindowController.swift new file mode 100644 index 0000000..ce0ab8f --- /dev/null +++ b/phpmon/Modules/PHP Config Editor/UI/ConfigManagerWindowController.swift @@ -0,0 +1,45 @@ +// +// ConfigManagerWindowController.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 12/09/2023. +// Copyright © 2023 Nico Verbruggen. All rights reserved. +// + +import Cocoa +import SwiftUI + +class PhpConfigManagerWindowController: PMWindowController { + + // MARK: - Window Identifier + + override var windowName: String { + return "ConfigManager" + } + + public static func create(delegate: NSWindowDelegate?) { + let windowController = Self() + windowController.window = NSWindow() + + guard let window = windowController.window else { return } + window.title = "" + window.styleMask = [.titled, .closable, .miniaturizable] + window.titlebarAppearsTransparent = true + window.delegate = delegate ?? windowController + window.contentView = NSHostingView(rootView: ConfigManagerView()) + window.setContentSize(NSSize(width: 600, height: 480)) + + App.shared.phpConfigManagerWindowController = windowController + } + + public static func show(delegate: NSWindowDelegate? = nil) { + if App.shared.phpConfigManagerWindowController == nil { + Self.create(delegate: delegate) + } + + App.shared.phpConfigManagerWindowController?.showWindow(self) + App.shared.phpConfigManagerWindowController?.window?.setCenterPosition(offsetY: 70) + + NSApp.activate(ignoringOtherApps: true) + } +} diff --git a/phpmon/en.lproj/Localizable.strings b/phpmon/en.lproj/Localizable.strings index 4c885ce..efc6d4f 100644 --- a/phpmon/en.lproj/Localizable.strings +++ b/phpmon/en.lproj/Localizable.strings @@ -13,6 +13,7 @@ "mi_fix_php_link" = "Fix Automatically..."; "mi_no_php_linked_explain" = "What's This?"; "mi_php_version_manager" = "PHP Version Manager..."; +"mi_php_config_manager" = "PHP Configuration Editor..."; "mi_diagnostics" = "Diagnostics"; "mi_active_services" = "Active Services"; From a6fa4b240f0e90497ae44660dea4b39512e5ef91 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Wed, 13 Sep 2023 18:13:51 +0200 Subject: [PATCH 02/12] =?UTF-8?q?=E2=9C=A8=20Allow=20editing=20of=20limits?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/Helpers/PMWindowController.swift | 2 +- phpmon/Common/PHP/PhpConfigurationFile.swift | 6 ++++ phpmon/Domain/Menu/StatusMenu+Items.swift | 13 ++++++-- .../PreferencesWindowController.swift | 2 +- .../SwiftUI/Menu/SectionHeaderView.swift | 1 + phpmon/Domain/SwiftUI/Menu/StatsView.swift | 18 +++++++++-- .../SwiftUI/Progress/ProgressWindowView.swift | 2 +- .../TerminalProgressWindowController.swift | 2 +- phpmon/Domain/Watcher/PhpConfigWatcher.swift | 19 +++++------ .../Data/BytePhpPreference.swift | 10 ++++-- .../Data/PhpPreference.swift | 2 +- .../PHP Config Editor/UI/ByteLimitView.swift | 32 +++++++++++++------ .../UI/ConfigManagerView.swift | 6 ++-- .../UI/ConfigManagerWindowController.swift | 3 +- .../PhpVersionManagerWindowController.swift | 2 +- phpmon/en.lproj/Localizable.strings | 4 ++- 16 files changed, 87 insertions(+), 37 deletions(-) diff --git a/phpmon/Common/Helpers/PMWindowController.swift b/phpmon/Common/Helpers/PMWindowController.swift index a8393d7..e42a92f 100644 --- a/phpmon/Common/Helpers/PMWindowController.swift +++ b/phpmon/Common/Helpers/PMWindowController.swift @@ -37,7 +37,7 @@ class PMWindowController: NSWindowController, NSWindowDelegate { extension NSWindowController { - public func positionWindowInTopLeftCorner(offsetY: CGFloat = 0, offsetX: CGFloat = 0) { + public func positionWindowInTopRightCorner(offsetY: CGFloat = 0, offsetX: CGFloat = 0) { guard let frame = NSScreen.main?.frame else { return } guard let window = self.window else { return } diff --git a/phpmon/Common/PHP/PhpConfigurationFile.swift b/phpmon/Common/PHP/PhpConfigurationFile.swift index 42d5165..8ba0dfa 100644 --- a/phpmon/Common/PHP/PhpConfigurationFile.swift +++ b/phpmon/Common/PHP/PhpConfigurationFile.swift @@ -96,10 +96,16 @@ class PhpConfigurationFile: CreatedFromFile { // Replace the specific line self.lines[item.lineIndex] = components.joined(separator: "=") + // Ensure the watchers aren't tripped up by config changes + PhpConfigWatcher.ignoresModificationsToConfigValues = true + // Finally, join the string and save the file atomatically again try self.lines.joined(separator: "\n") .write(toFile: self.filePath, atomically: true, encoding: .utf8) + // Ensure watcher behaviour is reverted + PhpConfigWatcher.ignoresModificationsToConfigValues = false + // Reload the original file self.reload() } diff --git a/phpmon/Domain/Menu/StatusMenu+Items.swift b/phpmon/Domain/Menu/StatusMenu+Items.swift index 6b6642e..366be92 100644 --- a/phpmon/Domain/Menu/StatusMenu+Items.swift +++ b/phpmon/Domain/Menu/StatusMenu+Items.swift @@ -152,9 +152,6 @@ extension StatusMenu { NSMenuItem(title: "mi_php_version_manager".localized, action: #selector(MainMenu.openPhpVersionManager), keyEquivalent: "m"), - NSMenuItem(title: "mi_php_config_manager".localized, - action: #selector(MainMenu.openConfigGUI), - keyEquivalent: "g"), NSMenuItem(title: "mi_php_config".localized, action: #selector(MainMenu.openActiveConfigFolder), keyEquivalent: "c"), @@ -203,6 +200,16 @@ extension StatusMenu { post: stats.post_max_size, upload: stats.upload_max_filesize) ) + + // TODO: As soon as this does more than just edit memory limits, move this + /* + addItem(NSMenuItem.separator()) + addItem(NSMenuItem( + title: "mi_manage_limits".localized, + action: #selector(MainMenu.openConfigGUI), + keyEquivalent: "l") + ) + */ } // MARK: - Extensions diff --git a/phpmon/Domain/Preferences/PreferencesWindowController.swift b/phpmon/Domain/Preferences/PreferencesWindowController.swift index 7c6fc75..501bd02 100644 --- a/phpmon/Domain/Preferences/PreferencesWindowController.swift +++ b/phpmon/Domain/Preferences/PreferencesWindowController.swift @@ -65,7 +65,7 @@ class PreferencesWindowController: PMWindowController { App.shared.preferencesWindowController?.showWindow(self) if justCreated { - App.shared.preferencesWindowController?.positionWindowInTopLeftCorner() + App.shared.preferencesWindowController?.positionWindowInTopRightCorner() } NSApp.activate(ignoringOtherApps: true) diff --git a/phpmon/Domain/SwiftUI/Menu/SectionHeaderView.swift b/phpmon/Domain/SwiftUI/Menu/SectionHeaderView.swift index e4feba5..01e2f2a 100644 --- a/phpmon/Domain/SwiftUI/Menu/SectionHeaderView.swift +++ b/phpmon/Domain/SwiftUI/Menu/SectionHeaderView.swift @@ -18,5 +18,6 @@ struct SectionHeaderView: View { .fontWeight(.medium) .foregroundColor(.appSecondary) .background(Color.debug) + .minimumScaleFactor(0.8) } } diff --git a/phpmon/Domain/SwiftUI/Menu/StatsView.swift b/phpmon/Domain/SwiftUI/Menu/StatsView.swift index edf8456..6059b3d 100644 --- a/phpmon/Domain/SwiftUI/Menu/StatsView.swift +++ b/phpmon/Domain/SwiftUI/Menu/StatsView.swift @@ -60,27 +60,39 @@ struct StatsView: View { .padding(.leading, 30) .padding(.trailing, 30) } else { - HStack(alignment: .firstTextBaseline, spacing: 30) { + HStack(alignment: .center, spacing: 10) { VStack(alignment: .center, spacing: 3) { SectionHeaderView(text: "mi_memory_limit".localized.uppercased()) Text(memoryLimit) .fontWeight(.medium) .font(.system(size: 16)) } + Divider() VStack(alignment: .center, spacing: 3) { SectionHeaderView(text: "mi_post_max_size".localized.uppercased()) Text(maxPostSize) .fontWeight(.medium) .font(.system(size: 16)) } + Divider() VStack(alignment: .center, spacing: 3) { SectionHeaderView(text: "mi_upload_max_filesize".localized.uppercased()) Text(maxUploadSize) .fontWeight(.medium) .font(.system(size: 16)) } + Divider().hidden() + Button { + Task { @MainActor in + MainMenu.shared.openConfigGUI() + } + } label: { + Image(systemName: "gearshape.fill") + } + .focusable(false) + .frame(minWidth: 30, alignment: .center) } - .padding(10) + .padding(5) .background(Color.debug) } } @@ -92,6 +104,6 @@ struct StatsView_Previews: PreviewProvider { memoryLimit: "1024 MB", maxPostSize: "1024 MB", maxUploadSize: "1024 MB" - ) + ).frame(height: 100) } } diff --git a/phpmon/Domain/SwiftUI/Progress/ProgressWindowView.swift b/phpmon/Domain/SwiftUI/Progress/ProgressWindowView.swift index d6edc7a..503802c 100644 --- a/phpmon/Domain/SwiftUI/Progress/ProgressWindowView.swift +++ b/phpmon/Domain/SwiftUI/Progress/ProgressWindowView.swift @@ -46,7 +46,7 @@ struct ProgressWindowView: View { window.contentView = NSHostingView(rootView: view) let controller = NSWindowController(window: window) controller.showWindow(nil) - controller.positionWindowInTopLeftCorner() + controller.positionWindowInTopRightCorner() controller.window?.makeKeyAndOrderFront(self) // NSApp.activate(ignoringOtherApps: true) return controller diff --git a/phpmon/Domain/Terminal Alert/TerminalProgressWindowController.swift b/phpmon/Domain/Terminal Alert/TerminalProgressWindowController.swift index 80298f8..5d4d3d3 100644 --- a/phpmon/Domain/Terminal Alert/TerminalProgressWindowController.swift +++ b/phpmon/Domain/Terminal Alert/TerminalProgressWindowController.swift @@ -20,7 +20,7 @@ class TerminalProgressWindowController: NSWindowController, NSWindowDelegate { windowController.showWindow(windowController) windowController.window?.makeKeyAndOrderFront(nil) - windowController.positionWindowInTopLeftCorner() + windowController.positionWindowInTopRightCorner() windowController.progressView?.labelTitle.stringValue = title windowController.progressView?.labelDescription.stringValue = description diff --git a/phpmon/Domain/Watcher/PhpConfigWatcher.swift b/phpmon/Domain/Watcher/PhpConfigWatcher.swift index 5634ac6..9a585f5 100644 --- a/phpmon/Domain/Watcher/PhpConfigWatcher.swift +++ b/phpmon/Domain/Watcher/PhpConfigWatcher.swift @@ -10,6 +10,8 @@ import Foundation class PhpConfigWatcher { + static var ignoresModificationsToConfigValues: Bool = false + let folderMonitorQueue = DispatchQueue(label: "FolderMonitorQueue", attributes: .concurrent) let url: URL @@ -23,7 +25,7 @@ class PhpConfigWatcher { init(for url: URL) { if FileSystem is TestableFileSystem { fatalError(""" - PhpConfigWatcher is not compatible with testable FS! " + PhpConfigWatcher is not compatible with testable FS!" You are not allowed to instantiate these while using a testable FS. """) } @@ -124,15 +126,14 @@ class FSWatcher { // Define the block to call when a file change is detected. folderMonitorSource?.setEventHandler { [weak self] in - // The default behaviour is to reload the menu - switch behaviour { - case .reloadsMenu: - // Default behaviour: reload the menu items - self?.parent.didChange?(self!.url) - case .reloadsWatchers: - // Alternative behaviour: reload all watchers - App.shared.handlePhpConfigWatcher(forceReload: true) + if behaviour == .reloadsWatchers + && !PhpConfigWatcher.ignoresModificationsToConfigValues { + // Reload all configuration watchers + return App.shared.handlePhpConfigWatcher(forceReload: true) } + + // The default behaviour is to reload the menu + self?.parent.didChange?(self!.url) } // Define a cancel handler to ensure the directory is closed when the source is cancelled. diff --git a/phpmon/Modules/PHP Config Editor/Data/BytePhpPreference.swift b/phpmon/Modules/PHP Config Editor/Data/BytePhpPreference.swift index 6509737..5bf4b33 100644 --- a/phpmon/Modules/PHP Config Editor/Data/BytePhpPreference.swift +++ b/phpmon/Modules/PHP Config Editor/Data/BytePhpPreference.swift @@ -52,8 +52,14 @@ class BytePhpPreference: PhpPreference { // MARK: Save Value private func updatedFieldValue() { - internalValue = "\(value)\(unit.rawValue)" - + if value == -1 { + // In case we're dealing with unlimited value, we don't need a unit + internalValue = "-1" + } else { + // We need to append the unit otherwise + internalValue = "\(value)\(unit.rawValue)" + } + do { try PhpPreference.persistToIniFile(key: self.key, value: self.internalValue) Log.info("The preference \(key) was updated to: \(value)") diff --git a/phpmon/Modules/PHP Config Editor/Data/PhpPreference.swift b/phpmon/Modules/PHP Config Editor/Data/PhpPreference.swift index a6d8fd3..438b952 100644 --- a/phpmon/Modules/PHP Config Editor/Data/PhpPreference.swift +++ b/phpmon/Modules/PHP Config Editor/Data/PhpPreference.swift @@ -18,7 +18,7 @@ class PhpPreference { internal static func persistToIniFile(key: String, value: String) throws { if let file = PhpEnvironments.shared.getConfigFile(forKey: key) { - try file.replace(key: key, value: value) + return try file.replace(key: key, value: value) } throw PhpConfigurationFile.ReplacementErrors.missingFile diff --git a/phpmon/Modules/PHP Config Editor/UI/ByteLimitView.swift b/phpmon/Modules/PHP Config Editor/UI/ByteLimitView.swift index c98c0d1..6178b66 100644 --- a/phpmon/Modules/PHP Config Editor/UI/ByteLimitView.swift +++ b/phpmon/Modules/PHP Config Editor/UI/ByteLimitView.swift @@ -35,12 +35,12 @@ struct PreferenceContainer: View { VStack(alignment: .leading) { controlView - Text(self.description.localizedForSwiftUI) + .lineLimit(nil) .font(.subheadline) + .foregroundColor(Color.secondary) .fixedSize(horizontal: false, vertical: true) } - .frame(maxWidth: .infinity, maxHeight: 150, alignment: .topLeading) } } .padding(5) @@ -51,6 +51,7 @@ struct ByteLimitView: View { @State private var unit: BytePhpPreference.UnitOption @State private var numberText: String @State private var unlimited: Bool + @State private var timer: Timer? private var preference: BytePhpPreference @@ -65,9 +66,11 @@ struct ByteLimitView: View { if !unlimited { HStack { TextField("", text: $numberText) - .onChange(of: numberText) { newText in - self.preference.value = Int(newText) ?? 256 - print(self.preference.internalValue) + .onChange(of: numberText) { [weak preference] newText in + timer?.invalidate() + timer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: false) { _ in + preference?.value = Int(newText) ?? 256 + } } Picker("Limit Name", selection: $unit) { ForEach(BytePhpPreference.UnitOption.allCases, id: \.self) { @@ -84,16 +87,27 @@ struct ByteLimitView: View { } Toggle(isOn: $unlimited) { - Label("Allow unlimited usage", systemImage: "heart").labelStyle(.titleOnly) - } + Text("confman.byte_limit.unlimited".localizedForSwiftUI) + }.onChange(of: unlimited, perform: { [weak preference] unlimited in + timer?.invalidate() + timer = Timer.scheduledTimer(withTimeInterval: 0.8, repeats: false) { _ in + preference?.value = unlimited ? -1 : 512 + preference?.unit = .megabyte + } + }) } } struct ByteLimitView_Previews: PreviewProvider { static var previews: some View { - PreferenceContainer(name: "Max Size", description: "Some maximum size") { + PreferenceContainer( + name: "Max Size", + description: + "Here's an extensive description that is obviously way too long but it should wrap." + + "The point of the wrapping text is that is allows us to see what's going on with the layout here." + ) { ByteLimitView(preference: BytePhpPreference(key: "max_memory")) - } + }.frame(width: 600, height: 200) ConfigManagerView() .frame(width: 600, height: .infinity) diff --git a/phpmon/Modules/PHP Config Editor/UI/ConfigManagerView.swift b/phpmon/Modules/PHP Config Editor/UI/ConfigManagerView.swift index 28d72f3..afcdd07 100644 --- a/phpmon/Modules/PHP Config Editor/UI/ConfigManagerView.swift +++ b/phpmon/Modules/PHP Config Editor/UI/ConfigManagerView.swift @@ -20,7 +20,7 @@ struct ConfigManagerView: View { var body: some View { VStack { HStack(alignment: .center, spacing: 15) { - Image(systemName: "square.and.pencil.circle.fill") + Image(systemName: "gearshape.fill") .resizable() .frame(width: 40, height: 40) .foregroundColor(Color.blue) @@ -69,7 +69,7 @@ struct ConfigManagerView: View { VStack(alignment: .trailing) { Button("Close", action: { - + App.shared.phpConfigManagerWindowController?.close() }) } .padding(.vertical, 10) @@ -80,7 +80,7 @@ struct ConfigManagerView: View { alignment: .topTrailing ) } - } + }.frame(maxHeight: 485) } } diff --git a/phpmon/Modules/PHP Config Editor/UI/ConfigManagerWindowController.swift b/phpmon/Modules/PHP Config Editor/UI/ConfigManagerWindowController.swift index ce0ab8f..95ba8f9 100644 --- a/phpmon/Modules/PHP Config Editor/UI/ConfigManagerWindowController.swift +++ b/phpmon/Modules/PHP Config Editor/UI/ConfigManagerWindowController.swift @@ -38,8 +38,9 @@ class PhpConfigManagerWindowController: PMWindowController { } App.shared.phpConfigManagerWindowController?.showWindow(self) - App.shared.phpConfigManagerWindowController?.window?.setCenterPosition(offsetY: 70) + App.shared.phpConfigManagerWindowController?.positionWindowInTopRightCorner() NSApp.activate(ignoringOtherApps: true) + App.shared.phpConfigManagerWindowController?.window?.makeKeyAndOrderFront(nil) } } diff --git a/phpmon/Modules/PHP Version Manager/UI/PhpVersionManagerWindowController.swift b/phpmon/Modules/PHP Version Manager/UI/PhpVersionManagerWindowController.swift index 57f45c9..5c66d8e 100644 --- a/phpmon/Modules/PHP Version Manager/UI/PhpVersionManagerWindowController.swift +++ b/phpmon/Modules/PHP Version Manager/UI/PhpVersionManagerWindowController.swift @@ -45,7 +45,7 @@ class PhpVersionManagerWindowController: PMWindowController { } App.shared.phpVersionManagerWindowController?.showWindow(self) - App.shared.phpVersionManagerWindowController?.positionWindowInTopLeftCorner() + App.shared.phpVersionManagerWindowController?.positionWindowInTopRightCorner() NSApp.activate(ignoringOtherApps: true) } diff --git a/phpmon/en.lproj/Localizable.strings b/phpmon/en.lproj/Localizable.strings index efc6d4f..d5716b2 100644 --- a/phpmon/en.lproj/Localizable.strings +++ b/phpmon/en.lproj/Localizable.strings @@ -14,6 +14,7 @@ "mi_no_php_linked_explain" = "What's This?"; "mi_php_version_manager" = "PHP Version Manager..."; "mi_php_config_manager" = "PHP Configuration Editor..."; +"mi_manage_limits" = "Manage Limits..."; "mi_diagnostics" = "Diagnostics"; "mi_active_services" = "Active Services"; @@ -85,7 +86,8 @@ // CONFMAN "confman.title" = "PHP Configuration Editor"; -"confman.description" = "This feature lets you customize your PHP installation with ease. Changes are automatically applied."; +"confman.description" = "This feature lets you customize your PHP installation's configuration with ease.\nPlease note that any changes you make are immediately and automatically applied."; +"confman.byte_limit.unlimited" = "Allow unlimited usage"; "php_ini.memory_limit.title" = "Memory Limit"; "php_ini.memory_limit.description" = "This sets the maximum amount of memory in bytes that a script is allowed to allocate. This helps prevent poorly written scripts for eating up all available memory on a server."; From 03c96a1d160726020a87064f168690c89645262a Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Tue, 19 Sep 2023 12:40:43 +0200 Subject: [PATCH 03/12] =?UTF-8?q?=F0=9F=91=8C=20Fixes=20after=20upgrading?= =?UTF-8?q?=20to=20Xcode=2015?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- phpmon/Common/Testables/TestableConfiguration.swift | 1 + phpmon/Domain/App/App+GlobalHotkey.swift | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/phpmon/Common/Testables/TestableConfiguration.swift b/phpmon/Common/Testables/TestableConfiguration.swift index 95e1423..d4c66e3 100644 --- a/phpmon/Common/Testables/TestableConfiguration.swift +++ b/phpmon/Common/Testables/TestableConfiguration.swift @@ -43,6 +43,7 @@ public struct TestableConfiguration: Codable { private var primaryPhpVersion: VersionNumber? private var secondaryPhpVersions: [VersionNumber] = [] + // swiftlint:disable function_body_length mutating func addPhpVersion(_ version: VersionNumber, primary: Bool) { if primary { if primaryPhpVersion != nil { diff --git a/phpmon/Domain/App/App+GlobalHotkey.swift b/phpmon/Domain/App/App+GlobalHotkey.swift index 8e2e129..a59701b 100644 --- a/phpmon/Domain/App/App+GlobalHotkey.swift +++ b/phpmon/Domain/App/App+GlobalHotkey.swift @@ -46,8 +46,10 @@ extension App { } hotkey.keyDownHandler = { - MainMenu.shared.statusItem.button?.performClick(nil) - NSApplication.shared.activate(ignoringOtherApps: true) + Task { @MainActor in + MainMenu.shared.statusItem.button?.performClick(nil) + NSApplication.shared.activate(ignoringOtherApps: true) + } } } From c6c3996c7b59c00752e256ceb67c6ba2bb620886 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Tue, 3 Oct 2023 20:37:47 +0200 Subject: [PATCH 04/12] =?UTF-8?q?=F0=9F=90=9B=20Fixed=20detection=20order?= =?UTF-8?q?=20(#263)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dictionary key order in Swift isn't a thing, so the process is now a two-pronged approach: 1) check for specific apps, 2) check for specific broad frameworks after no other matches were made. Previously, detection would only work correctly some of the time. Also cleaned up the `getNotableDependencies()` method. --- PHP Monitor.xcodeproj/project.pbxproj | 32 ++++----- .../Integrations/Composer/ComposerJson.swift | 9 +-- ...works.swift => ProjectTypeDetection.swift} | 65 +++++++++---------- .../Integrations/Valet/Sites/ValetSite.swift | 18 +++-- 4 files changed, 66 insertions(+), 58 deletions(-) rename phpmon/Domain/Integrations/Composer/{PhpFrameworks.swift => ProjectTypeDetection.swift} (78%) diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 49c32df..dcd8763 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -92,8 +92,8 @@ C40FE73B282ABB2E00A302C2 /* AppVersionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE739282ABB2E00A302C2 /* AppVersionTest.swift */; }; C412E5FC25700D5300A1FB67 /* HomebrewDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C412E5FB25700D5300A1FB67 /* HomebrewDecodable.swift */; }; C413E43528DA3EB100AE33C7 /* TestableShellTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C413E43428DA3EB100AE33C7 /* TestableShellTest.swift */; }; - C415937F27A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; - C415938027A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; + C415937F27A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */; }; + C415938027A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */; }; C4159AF728E4D40400545349 /* RealShellTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4159AF628E4D40400545349 /* RealShellTest.swift */; }; C415D3B72770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; }; C415D3B82770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; }; @@ -343,10 +343,10 @@ C471E81E28F9BB260021E251 /* BetterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */; }; C471E81F28F9BB290021E251 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; }; C471E82028F9BB290021E251 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; }; - C471E82128F9BB2E0021E251 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; + C471E82128F9BB2E0021E251 /* ProjectTypeDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */; }; C471E82228F9BB2E0021E251 /* ComposerWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */; }; C471E82328F9BB2E0021E251 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; }; - C471E82428F9BB2E0021E251 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; + C471E82428F9BB2E0021E251 /* ProjectTypeDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */; }; C471E82528F9BB2E0021E251 /* ComposerWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */; }; C471E82628F9BB2E0021E251 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; }; C471E82728F9BB310021E251 /* BrewDiagnostics.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F2E4362752F0870020E974 /* BrewDiagnostics.swift */; }; @@ -898,7 +898,7 @@ C40FE739282ABB2E00A302C2 /* AppVersionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersionTest.swift; sourceTree = ""; }; C412E5FB25700D5300A1FB67 /* HomebrewDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewDecodable.swift; sourceTree = ""; }; C413E43428DA3EB100AE33C7 /* TestableShellTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableShellTest.swift; sourceTree = ""; }; - C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpFrameworks.swift; sourceTree = ""; }; + C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectTypeDetection.swift; sourceTree = ""; }; C4159AF628E4D40400545349 /* RealShellTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealShellTest.swift; sourceTree = ""; }; C415D3B62770F294005EF286 /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = ""; }; C415D3E72770F692005EF286 /* AppDelegate+InterApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+InterApp.swift"; sourceTree = ""; }; @@ -1983,7 +1983,7 @@ children = ( C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */, C4D89BC52783C99400A02B68 /* ComposerJson.swift */, - C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */, + C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */, ); path = Composer; sourceTree = ""; @@ -2478,7 +2478,7 @@ C4B97B78275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */, C4CE3BB827B31F2E0086CA49 /* MainMenu+Switcher.swift in Sources */, C456A0CB2AA6166F0080144F /* BytePhpPreference.swift in Sources */, - C415937F27A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */, + C415937F27A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */, C4811D2422D70A4700B5F6B3 /* App.swift in Sources */, C44DFA7C2A67043000B98ED5 /* ConfigManagerView.swift in Sources */, C40934A2298EEB2C00D25014 /* CaskFile.swift in Sources */, @@ -2724,7 +2724,7 @@ C471E81828F9BAE80021E251 /* StringExtension.swift in Sources */, C471E7FA28F9BACB0021E251 /* InternalSwitcher.swift in Sources */, C471E82628F9BB2E0021E251 /* ComposerJson.swift in Sources */, - C471E82428F9BB2E0021E251 /* PhpFrameworks.swift in Sources */, + C471E82428F9BB2E0021E251 /* ProjectTypeDetection.swift in Sources */, C471E7E828F9BAC20021E251 /* Actions.swift in Sources */, C40D72612A018AE30054A067 /* BrewFormula+UI.swift in Sources */, C471E82528F9BB2E0021E251 /* ComposerWindow.swift in Sources */, @@ -2923,7 +2923,7 @@ C48DDD1029C75C9E00D032D9 /* BlockingOverlayView.swift in Sources */, C471E7F828F9BACB0021E251 /* InternalSwitcher.swift in Sources */, C471E82328F9BB2E0021E251 /* ComposerJson.swift in Sources */, - C471E82128F9BB2E0021E251 /* PhpFrameworks.swift in Sources */, + C471E82128F9BB2E0021E251 /* ProjectTypeDetection.swift in Sources */, C471E7EF28F9BAC30021E251 /* Actions.swift in Sources */, C471E82228F9BB2E0021E251 /* ComposerWindow.swift in Sources */, C4D3660E29113F20006BD146 /* System.swift in Sources */, @@ -3121,7 +3121,7 @@ C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */, C4B79EBD29CA38DB00A483EE /* BrewCommand.swift in Sources */, C485707828BF456300539B36 /* Warning.swift in Sources */, - C415938027A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */, + C415938027A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */, C40F505628ECA64E004AD45B /* TestableConfigurations.swift in Sources */, C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */, C449B4F227EE7FC400C47E8A /* DomainListPhpCell.swift in Sources */, @@ -3492,7 +3492,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1320; + CURRENT_PROJECT_VERSION = 1325; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3523,7 +3523,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1320; + CURRENT_PROJECT_VERSION = 1325; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3763,7 +3763,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1320; + CURRENT_PROJECT_VERSION = 1325; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3879,7 +3879,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1320; + CURRENT_PROJECT_VERSION = 1325; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3995,7 +3995,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1320; + CURRENT_PROJECT_VERSION = 1325; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -4176,7 +4176,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1320; + CURRENT_PROJECT_VERSION = 1325; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; diff --git a/phpmon/Domain/Integrations/Composer/ComposerJson.swift b/phpmon/Domain/Integrations/Composer/ComposerJson.swift index 1e3047e..29bf866 100644 --- a/phpmon/Domain/Integrations/Composer/ComposerJson.swift +++ b/phpmon/Domain/Integrations/Composer/ComposerJson.swift @@ -62,12 +62,13 @@ struct ComposerJson: Decodable { public func getNotableDependencies() -> [String: String] { var notable: [String: String] = [:] - var scan = Array(PhpFrameworks.DependencyList.keys) - scan.append("php") + let scan = Array(ProjectTypeDetection.CommonDependencyList.keys) + + Array(ProjectTypeDetection.SpecificDependencyList.keys) + + ["php"] scan.forEach { dependency in - if dependencies?[dependency] != nil { - notable[dependency] = dependencies![dependency] + if let resolvedDependency = dependencies?[dependency] { + notable[dependency] = resolvedDependency } } diff --git a/phpmon/Domain/Integrations/Composer/PhpFrameworks.swift b/phpmon/Domain/Integrations/Composer/ProjectTypeDetection.swift similarity index 78% rename from phpmon/Domain/Integrations/Composer/PhpFrameworks.swift rename to phpmon/Domain/Integrations/Composer/ProjectTypeDetection.swift index 2dfd435..cd8fedc 100644 --- a/phpmon/Domain/Integrations/Composer/PhpFrameworks.swift +++ b/phpmon/Domain/Integrations/Composer/ProjectTypeDetection.swift @@ -8,20 +8,20 @@ import Foundation -struct PhpFrameworks { - +struct ProjectTypeDetection { /** - This list should probably be reversed when checked, because some of these - will also require either `laravel/framework` or `symfony/symfony`. + This list is only checked if the specific dependency list doesn't report a match. */ - public static let DependencyList = [ - - // COMMON FRAMEWORKS + public static let CommonDependencyList = [ "laravel/framework": "Laravel", "symfony/symfony": "Symfony", - "laravel/lumen": "Lumen", + "laravel/lumen": "Lumen" + ] - // VARIOUS CMS + /** + This list is checked first to see if a project dependency can be mapped to a certain project type. + */ + public static let SpecificDependencyList = [ "roots/bedrock": "Bedrock", "cakephp/app": "CakePHP", "craftcms/craft": "Craft", @@ -37,30 +37,8 @@ struct PhpFrameworks { "johnpbloch/wordpress-core": "WordPress", "zendframework/zendframework": "Zend", "zendframework/zend-mvc": "Zend", - "typo3/cms-core": "Typo3" - // "magento/*": "Magento", - // "concrete5/*": "Concrete5", - // "contao/*": "Contao", - // "slim/*": "Slim", - ] - - public static let FileMapping: [String: [String]] = [ - "Drupal": [ - // Legacy installations - "/misc/drupal.js", - "/core/lib/Drupal.php", - // The default (new) installation w/ Composer puts the modules in /web - "/web/misc/drupal.js", - "/web/core/lib/Drupal.php" - ], - "WordPress": [ - "/wp-config.php", - "/wp-config-sample.php" - ], - "Typo3": [ - "/typo3", - "/public/typo3" - ] + "typo3/cms-core": "Typo3", + "slim/slim": "Slim" ] /** @@ -82,4 +60,25 @@ struct PhpFrameworks { return nil } + /** + File mapping is used as a fallback if neither specific nor framework matches could be done. + */ + public static let FileMapping: [String: [String]] = [ + "Drupal": [ + // Legacy installations + "/misc/drupal.js", + "/core/lib/Drupal.php", + // The default (new) installation w/ Composer puts the modules in /web + "/web/misc/drupal.js", + "/web/core/lib/Drupal.php" + ], + "WordPress": [ + "/wp-config.php", + "/wp-config-sample.php" + ], + "Typo3": [ + "/typo3", + "/public/typo3" + ] + ] } diff --git a/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift b/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift index 0ba1610..df04e93 100644 --- a/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift +++ b/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift @@ -141,7 +141,7 @@ class ValetSite: ValetListable { self.determineDriverViaComposer() if self.driver == nil { - self.driver = PhpFrameworks.detectFallbackDependency(self.absolutePath) + self.driver = ProjectTypeDetection.detectFallbackDependency(self.absolutePath) } } @@ -155,10 +155,18 @@ class ValetSite: ValetListable { private func determineDriverViaComposer() { self.driverDeterminedByComposer = true - PhpFrameworks.DependencyList.reversed().forEach { (key: String, value: String) in - if self.notableComposerDependencies.keys.contains(key) { - self.driver = value - } + // First, check specific dependencies + for (key, value) in ProjectTypeDetection.SpecificDependencyList.reversed() + where self.notableComposerDependencies.keys.contains(key) { + self.driver = value + return + } + + // After that, check for generic frameworks if no match was made + for (key, value) in ProjectTypeDetection.CommonDependencyList.reversed() + where self.notableComposerDependencies.keys.contains(key) { + self.driver = value + return } } From 7cba25b52e9d736487c2a768870dcd004657166d Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Tue, 3 Oct 2023 20:40:59 +0200 Subject: [PATCH 05/12] =?UTF-8?q?=F0=9F=91=8C=20Cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift b/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift index df04e93..7c2c8ba 100644 --- a/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift +++ b/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift @@ -155,16 +155,14 @@ class ValetSite: ValetListable { private func determineDriverViaComposer() { self.driverDeterminedByComposer = true - // First, check specific dependencies - for (key, value) in ProjectTypeDetection.SpecificDependencyList.reversed() - where self.notableComposerDependencies.keys.contains(key) { + for (key, value) in ProjectTypeDetection.SpecificDependencyList + where notableComposerDependencies.keys.contains(key) { self.driver = value return } - // After that, check for generic frameworks if no match was made - for (key, value) in ProjectTypeDetection.CommonDependencyList.reversed() - where self.notableComposerDependencies.keys.contains(key) { + for (key, value) in ProjectTypeDetection.CommonDependencyList + where notableComposerDependencies.keys.contains(key) { self.driver = value return } From 9a35014d2a0699948edb89541306ed7300288c04 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Sat, 7 Oct 2023 13:01:06 +0200 Subject: [PATCH 06/12] =?UTF-8?q?=E2=9C=A8=20Warn=20about=20Laravel=20Herd?= =?UTF-8?q?=20running=20&=20conflicts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's perfectly possible to run Laravel Valet (standalone) and Laravel Herd side-by-side or mix usage, but it's not recommended and/or supported (especially since Herd recommends migrating away from regular Valet and may terminate Valet's services). To avoid issues, PHP Monitor won't work if Herd is currently running. It's totally fine to relaunch Herd after PHP Monitor's done starting up, since the check only happens at launch. Also, PHP Monitor warns about the PATH changes in `~/.zshrc` after installing Laravel Herd, because that may impact the usage of PHP aliases/global PHP version in terminal provided by PHP Monitor. --- phpmon/Domain/App/Startup.swift | 14 ++++++++++++++ phpmon/de.lproj/Localizable.strings | 5 +++++ phpmon/en.lproj/Localizable.strings | 5 +++++ phpmon/nl.lproj/Localizable.strings | 5 +++++ phpmon/pt-PT.lproj/Localizable.strings | 5 +++++ phpmon/vi.lproj/Localizable.strings | 5 +++++ 6 files changed, 39 insertions(+) diff --git a/phpmon/Domain/App/Startup.swift b/phpmon/Domain/App/Startup.swift index cea3bbf..a130f63 100644 --- a/phpmon/Domain/App/Startup.swift +++ b/phpmon/Domain/App/Startup.swift @@ -241,6 +241,20 @@ class Startup { descriptionText: "startup.errors.which_alias_issue.desc".localized ), // ================================================================================= + // Determine that Laravel Herd is not running (may cause conflicts) + // ================================================================================= + EnvironmentCheck( + command: { + return NSWorkspace.shared.runningApplications.contains(where: { app in + return app.bundleIdentifier == "de.beyondco.herd" + }) + }, + name: "Herd is not running", + titleText: "startup.errors.herd_running.title".localized, + subtitleText: "startup.errors.herd_running.subtitle".localized, + descriptionText: "startup.errors.herd_running.desc".localized + ), + // ================================================================================= // Determine that Valet works correctly (no issues in platform detected) // ================================================================================= EnvironmentCheck( diff --git a/phpmon/de.lproj/Localizable.strings b/phpmon/de.lproj/Localizable.strings index 1817b30..de087a7 100644 --- a/phpmon/de.lproj/Localizable.strings +++ b/phpmon/de.lproj/Localizable.strings @@ -653,6 +653,11 @@ Wenn Sie diese Meldung sehen, aber nicht wissen, warum dieser Ordner verschwunde "startup.errors.which_alias_issue.subtitle" = "Es scheint, dass es eine Datei in `/usr/local/bin/which` gibt. Diese wird normalerweise von NodeJS eingerichtet, aber `node` ist nicht im PATH in `/usr/local/bin`. Um dies zu beheben, lesen Sie weiter."; "startup.errors.which_alias_issue.desc" = "Sie müssen einen Symlink von `node` in das Verzeichnis `/usr/local/bin` setzen, um sicherzustellen, dass PHP Monitor erfolgreich starten kann. Für weitere Informationen siehe: https://github.com/nicoverbruggen/phpmon/issues/174"; +// Laravel Herd conflicts +"startup.errors.herd_running.title" = "Laravel Herd scheint aktiv zu sein"; +"startup.errors.herd_running.subtitle" = "Es scheint, dass Laravel Herd derzeit aktiv ist. Die integrierte Valet-Konfiguration von Herd kann mit Ihrer regulären Valet-Installation kollidieren. Beenden Sie daher Herd, bevor Sie fortfahren. (Sie können Herd und reguläres Valet problemlos kombinieren, sollten sie jedoch nicht gleichzeitig ausführen.)"; +"startup.errors.herd_running.desc" = "Möglicherweise stellt der von Herd zu Ihrem $PATH hinzugefügte `php`-Alias eine Behinderung für das Aliasen von PHP Monitor als `php` dar. Beachten Sie dies bitte. Schauen Sie in die Datei `~/.zshrc`, um zu sehen, was Herd zu Ihrem $PATH hinzugefügt hat."; + // Warning about a different PHP version linked than last time "startup.version_mismatch.title" = "Die aktive PHP-Version hat sich geändert."; "startup.version_mismatch.subtitle" = "Seitdem PHP Monitor das letzte Mal aktiv war, wurde Ihre verlinkte PHP-Version auf PHP %@ geändert. Möchten Sie zurück zu PHP %@ wechseln oder möchten Sie die aktuelle Version weiter verwenden?"; diff --git a/phpmon/en.lproj/Localizable.strings b/phpmon/en.lproj/Localizable.strings index d5716b2..bd5c8dd 100644 --- a/phpmon/en.lproj/Localizable.strings +++ b/phpmon/en.lproj/Localizable.strings @@ -670,6 +670,11 @@ If you are seeing this message but are confused why this folder has gone missing "startup.errors.which_alias_issue.subtitle" = "It appears that there's a file in `/usr/local/bin/which`. This is usually set up by NodeJS, but `node` isn't in the PATH in `/usr/local/bin`. To fix this, keep reading."; "startup.errors.which_alias_issue.desc" = "You will need to symlink `node` into the `/usr/local/bin` directory to make sure PHP Monitor can start successfully. For more info, see: https://github.com/nicoverbruggen/phpmon/issues/174"; +/// Laravel Herd conflicts +"startup.errors.herd_running.title" = "Laravel Herd appears to be running"; +"startup.errors.herd_running.subtitle" = "It seems that Laravel Herd is currently running. Herd's built-in Valet setup may conflict with your regular Valet installation, so please quit Herd before continuing. (You can perfectly mix usage of Herd and regular Valet but you shouldn't run both at the same time.)"; +"startup.errors.herd_running.desc" = "You may also find that the `php` alias by Herd added to your $PATH may prevent `php` aliasing of PHP Monitor from working, so keep that in mind. You can check out `~/.zshrc` and see what Herd has added to your $PATH."; + // Warning about a different PHP version linked than last time "startup.version_mismatch.title" = "Your active PHP version has changed."; "startup.version_mismatch.subtitle" = "Since PHP Monitor was last active, your linked PHP version has been changed to PHP %@. Would you like to switch back to PHP %@, or do you want to keep using the current version?"; diff --git a/phpmon/nl.lproj/Localizable.strings b/phpmon/nl.lproj/Localizable.strings index 7af41e9..c118a6e 100644 --- a/phpmon/nl.lproj/Localizable.strings +++ b/phpmon/nl.lproj/Localizable.strings @@ -652,6 +652,11 @@ Als u dit bericht ziet, maar verward bent waarom deze map ontbreekt, wilt u moge "startup.errors.which_alias_issue.subtitle" = "Het lijkt erop dat er een bestand is in `/usr/local/bin/which`. Dit wordt meestal ingesteld door NodeJS, maar `node` staat niet in de PATH in `/usr/local/bin`. Om dit op te lossen, gaat u verder met lezen."; "startup.errors.which_alias_issue.desc" = "U moet `node` symbolisch koppelen aan de `/usr/local/bin`-directory om ervoor te zorgen dat PHP Monitor succesvol kan starten. Voor meer informatie, zie: https://github.com/nicoverbruggen/phpmon/issues/174"; +/// Laravel Herd conflicts +"startup.errors.herd_running.title" = "Laravel Herd lijkt actief te zijn"; +"startup.errors.herd_running.subtitle" = "Het lijkt erop dat Laravel Herd momenteel actief is. De ingebouwde Valet-configuratie van Herd kan conflicteren met je reguliere Valet-installatie, dus sluit Herd af voordat je verdergaat. (Je kunt perfect gebruik maken van zowel Herd als reguliere Valet, maar je moet ze niet tegelijkertijd uitvoeren.)"; +"startup.errors.herd_running.desc" = "Je kan ook merken dat de `php`-alias die Herd aan je $PATH heeft toegevoegd, niet werkt met de aliases van PHP Monitor, dus hou daar rekening mee. Je kunt `~/.zshrc` bekijken om te zien wat Herd aan je $PATH heeft toegevoegd."; + // Warning about a different PHP version linked than last time "startup.version_mismatch.title" = "Uw actieve PHP-versie is gewijzigd."; "startup.version_mismatch.subtitle" = "Sinds PHP Monitor voor het laatst actief was, is uw gekoppelde PHP-versie gewijzigd naar PHP %@. Wilt u terugschakelen naar PHP %@, of wilt u de huidige versie blijven gebruiken?"; diff --git a/phpmon/pt-PT.lproj/Localizable.strings b/phpmon/pt-PT.lproj/Localizable.strings index 9005bbe..71cccf5 100644 --- a/phpmon/pt-PT.lproj/Localizable.strings +++ b/phpmon/pt-PT.lproj/Localizable.strings @@ -652,6 +652,11 @@ Se ainda vê esta mensagem, e não percebe porque a diretoria desapareceu, conv "startup.errors.which_alias_issue.subtitle" = "Parece que há um ficheiro em `/usr/local/bin/which`. Isto geralmente é configurado pelo NodeJS, mas `node` não está no PATH em `/usr/local/bin`. Para corrigir isto, continue a ler."; "startup.errors.which_alias_issue.desc" = "Precisará vincular `node` à diretoria `/usr/local/bin` para garantir que o PHP Monitor possa iniciar com sucesso. Para mais informações, consulte: https://github.com/nicoverbruggen/phpmon/issues/174"; +// Laravel Herd conflicts +"startup.errors.herd_running.title" = "O Laravel Herd parece estar em execução"; +"startup.errors.herd_running.subtitle" = "Parece que o Laravel Herd está atualmente em execução. A configuração integrada do Valet do Herd pode entrar em conflito com a sua instalação regular do Valet. Por favor, encerre o Herd antes de continuar. (Você pode combinar perfeitamente o uso do Herd e do Valet regular, mas não deve executar ambos ao mesmo tempo.)"; +"startup.errors.herd_running.desc" = "Você também pode perceber que o alias `php` adicionado pelo Herd ao seu $PATH pode impedir o aliasing do PHP Monitor como `php`, então tenha isso em mente. Você pode verificar o arquivo `~/.zshrc` para ver o que o Herd adicionou ao seu $PATH."; + // Warning about a different PHP version linked than last time "startup.version_mismatch.title" = "A sua versão vinculada do PHP mudou."; "startup.version_mismatch.subtitle" = "Desde que o PHP Monitor esteve ativo a última vez, a sua versão do PHP vinculada foi alterada para PHP %@. Gostaria de voltar para o PHP %@ ou deseja continuar a usar a versão atual?"; diff --git a/phpmon/vi.lproj/Localizable.strings b/phpmon/vi.lproj/Localizable.strings index ab2daf9..e97c28e 100644 --- a/phpmon/vi.lproj/Localizable.strings +++ b/phpmon/vi.lproj/Localizable.strings @@ -646,6 +646,11 @@ Nếu bạn nhìn thấy thông báo này nhưng bối rối vì thư mục này "startup.errors.which_alias_issue.subtitle" = "Dường như có một tệp trong `/usr/local/bin/which`. Điều này thường được thiết lập bởi NodeJS, nhưng `node` không có trong PATH trong `/usr/local/bin`. Để khắc phục điều này, hãy đọc tiếp."; "startup.errors.which_alias_issue.desc" = "Bạn sẽ cần tạo liên kết tượng trưng cho `node` vào thư mục `/usr/local/bin` để đảm bảo PHP Monitor có thể khởi động thành công. Để biết thêm thông tin, xem: https://github.com/nicoverbruggen/phpmon/issues/174"; +/// Laravel Herd conflicts +"startup.errors.herd_running.title" = "Có vẻ như Laravel Herd đang chạy"; +"startup.errors.herd_running.subtitle" = "Có vẻ như Laravel Herd hiện đang chạy. Cài đặt Valet tích hợp của Herd có thể xung đột với cài đặt Valet thông thường của bạn, vì vậy hãy thoát Herd trước khi tiếp tục. (Bạn có thể hoàn toàn kết hợp sử dụng Herd và Valet thông thường nhưng bạn không nên chạy cả hai cùng một lúc.)"; +"startup.errors.herd_running.desc" = "Bạn cũng có thể thấy rằng bí danh `php` mà Herd thêm vào $PATH của bạn có thể ngăn chặn việc đặt bí danh `php` cho PHP Monitor hoạt động, vì vậy hãy lưu ý điều đó. Bạn có thể kiểm tra tệp `~/.zshrc` và xem Herd đã thêm gì vào $PATH của bạn."; + // Warning about a different PHP version linked than last time "startup.version_mismatch.title" = "Phiên bản PHP đang hoạt động của bạn đã thay đổi."; "startup.version_mismatch.subtitle" = "Kể từ khi PHP Monitor hoạt động lần cuối, phiên bản PHP được liên kết của bạn đã được thay đổi thành PHP %@. Bạn có muốn chuyển lại sang PHP %@ không, hay bạn muốn tiếp tục sử dụng phiên bản hiện tại?"; From 00b4760b85632ffc1d3e88915994ef30e279e63c Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Sat, 7 Oct 2023 13:02:56 +0200 Subject: [PATCH 07/12] =?UTF-8?q?=F0=9F=94=A7=20Bump=20build=20to=201330?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index dcd8763..283cad4 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -3492,7 +3492,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1325; + CURRENT_PROJECT_VERSION = 1330; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3523,7 +3523,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1325; + CURRENT_PROJECT_VERSION = 1330; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3763,7 +3763,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1325; + CURRENT_PROJECT_VERSION = 1330; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3879,7 +3879,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1325; + CURRENT_PROJECT_VERSION = 1330; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3995,7 +3995,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1325; + CURRENT_PROJECT_VERSION = 1330; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -4176,7 +4176,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1325; + CURRENT_PROJECT_VERSION = 1330; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; From b9c7cdb3cc3b3eafa8e5b2ca7eb455e406565a23 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Fri, 20 Oct 2023 17:34:19 +0200 Subject: [PATCH 08/12] =?UTF-8?q?=E2=9C=A8=20Generate=20Fish-friendly=20sc?= =?UTF-8?q?ripts=20(#264)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 12 +++++----- phpmon/Common/Core/Paths.swift | 7 ++++++ phpmon/Common/Helpers/System.swift | 8 +++++++ phpmon/Common/PHP/PHP Version/PhpHelper.swift | 24 ++++++++++++++++--- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 283cad4..7ee0407 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -3492,7 +3492,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1330; + CURRENT_PROJECT_VERSION = 1335; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3523,7 +3523,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1330; + CURRENT_PROJECT_VERSION = 1335; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3763,7 +3763,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1330; + CURRENT_PROJECT_VERSION = 1335; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3879,7 +3879,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1330; + CURRENT_PROJECT_VERSION = 1335; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3995,7 +3995,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1330; + CURRENT_PROJECT_VERSION = 1335; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -4176,7 +4176,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1330; + CURRENT_PROJECT_VERSION = 1335; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; diff --git a/phpmon/Common/Core/Paths.swift b/phpmon/Common/Core/Paths.swift index 41bfda9..1ea5579 100644 --- a/phpmon/Common/Core/Paths.swift +++ b/phpmon/Common/Core/Paths.swift @@ -17,6 +17,7 @@ public class Paths { internal var baseDir: Paths.HomebrewDir private var userName: String + private var preferredShell: String init() { // Assume the default directory is correct @@ -31,9 +32,11 @@ public class Paths { } userName = identity() + preferredShell = preferred_shell() if !isRunningSwiftUIPreview { Log.info("The current username is `\(userName)`.") + Log.info("The user's shell is `\(preferredShell)`.") } } @@ -104,6 +107,10 @@ public class Paths { + (App.identifier.contains(".dev") ? "phpmon-dev" : "phpmon") } + public static var shell: String { + return shared.preferredShell + } + // MARK: - Flexible Binaries // (these can be in multiple locations, so we scan common places because) // (PHP Monitor will not use the user's own PATH) diff --git a/phpmon/Common/Helpers/System.swift b/phpmon/Common/Helpers/System.swift index f3a1305..5bbba22 100644 --- a/phpmon/Common/Helpers/System.swift +++ b/phpmon/Common/Helpers/System.swift @@ -65,3 +65,11 @@ public func identity() -> String { return output.trimmingCharacters(in: .whitespacesAndNewlines) } + +/** + Retrieves the user's preferred shell. + */ +public func preferred_shell() -> String { + return system("dscl . -read ~/ UserShell | sed 's/UserShell: //'") + .trimmingCharacters(in: .whitespacesAndNewlines) +} diff --git a/phpmon/Common/PHP/PHP Version/PhpHelper.swift b/phpmon/Common/PHP/PHP Version/PhpHelper.swift index be41b47..dce0c59 100644 --- a/phpmon/Common/PHP/PHP Version/PhpHelper.swift +++ b/phpmon/Common/PHP/PHP Version/PhpHelper.swift @@ -49,8 +49,10 @@ class PhpHelper { let path = URL(fileURLWithPath: "\(Paths.optPath)/php@\(version)/bin") .resolvingSymlinksInPath().path - // The contents of the script! - let script = script(path, keyPhrase, version, dotless) + // Check if the user uses Fish + let script = Paths.shell.contains("/fish") + ? fishScript(path, keyPhrase, version, dotless) + : zshScript(path, keyPhrase, version, dotless) Task { @MainActor in try FileSystem.writeAtomicallyToFile(destination, content: script) @@ -78,7 +80,7 @@ class PhpHelper { } } - private static func script( + private static func zshScript( _ path: String, _ keyPhrase: String, _ version: String, @@ -96,6 +98,22 @@ class PhpHelper { """ } + private static func fishScript( + _ path: String, + _ keyPhrase: String, + _ version: String, + _ dotless: String + ) -> String { + return """ + #!\(Paths.binPath)/fish + # \(keyPhrase) + # It reflects the location of PHP \(version)'s binaries on your system. + # Usage: . pm\(dotless) + echo "PHP Monitor has enabled this terminal to use PHP \(version)."; \\ + set -x PATH \(path) $PATH + """ + } + private static func createSymlink(_ dotless: String) async { let source = "\(Paths.homePath)/.config/phpmon/bin/pm\(dotless)" let destination = "/usr/local/bin/pm\(dotless)" From 5594130ccd8c17295b311aef982b5d7f71b877ce Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Tue, 24 Oct 2023 18:24:18 +0200 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=91=8C=20Cleanup=20filesystem=20wat?= =?UTF-8?q?cher=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 44 +++-- phpmon/Common/PHP/PhpConfigurationFile.swift | 4 +- phpmon/Domain/App/App.swift | 13 +- phpmon/Domain/Watcher/App+BrewWatch.swift | 17 +- phpmon/Domain/Watcher/App+ConfigWatch.swift | 32 ++-- phpmon/Domain/Watcher/ConfigFSNotifier.swift | 77 +++++++++ .../Domain/Watcher/ConfigWatchManager.swift | 82 +++++++++ .../Watcher}/FSNotifier.swift | 6 +- phpmon/Domain/Watcher/PhpConfigWatcher.swift | 155 ------------------ 9 files changed, 223 insertions(+), 207 deletions(-) create mode 100644 phpmon/Domain/Watcher/ConfigFSNotifier.swift create mode 100644 phpmon/Domain/Watcher/ConfigWatchManager.swift rename phpmon/{Common/Helpers => Domain/Watcher}/FSNotifier.swift (95%) delete mode 100644 phpmon/Domain/Watcher/PhpConfigWatcher.swift diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 7ee0407..f45a157 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -162,6 +162,10 @@ C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F627E258410045BD4E /* DomainListPhpCell.swift */; }; C44067F927E2585E0045BD4E /* DomainListTypeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */; }; C44067FB27E25FD70045BD4E /* DomainListTLSCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */; }; + C441CC562AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */; }; + C441CC572AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */; }; + C441CC582AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */; }; + C441CC592AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */; }; C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */; }; C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */; }; C4463FCC29804BCB007B93D5 /* RCFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4463FCB29804BCB007B93D5 /* RCFile.swift */; }; @@ -424,7 +428,7 @@ C471E87828F9BB650021E251 /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; }; C471E87928F9BB650021E251 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; }; C471E87B28F9BB650021E251 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; - C471E87C28F9BB650021E251 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; + C471E87C28F9BB650021E251 /* ConfigWatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */; }; C471E87D28F9BB650021E251 /* Preset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C5C9B2846A40600E28255 /* Preset.swift */; }; C471E87E28F9BB650021E251 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; }; C471E87F28F9BB650021E251 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4297F7928970D59004C4630 /* WarningView.swift */; }; @@ -512,7 +516,7 @@ C471E8DB28F9BB8F0021E251 /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; }; C471E8DC28F9BB8F0021E251 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; }; C471E8DE28F9BB8F0021E251 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; - C471E8DF28F9BB8F0021E251 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; + C471E8DF28F9BB8F0021E251 /* ConfigWatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */; }; C471E8E028F9BB8F0021E251 /* Preset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C5C9B2846A40600E28255 /* Preset.swift */; }; C471E8E128F9BB8F0021E251 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; }; C471E8E228F9BB8F0021E251 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4297F7928970D59004C4630 /* WarningView.swift */; }; @@ -678,8 +682,8 @@ C4C8900728F0E3EF00CE5E97 /* ActiveFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8900628F0E3EF00CE5E97 /* ActiveFileSystem.swift */; }; C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; - C4C8E81B276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; - C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; + C4C8E81B276F54E5003AC782 /* ConfigWatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */; }; + C4C8E81C276F54E5003AC782 /* ConfigWatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */; }; C4CB250529B28BB800CA4492 /* MainMenuTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB250429B28BB800CA4492 /* MainMenuTest.swift */; }; C4CB6E65292C362C002E9027 /* Homebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB6E64292C362C002E9027 /* Homebrew.swift */; }; C4CB6E66292C362C002E9027 /* Homebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB6E64292C362C002E9027 /* Homebrew.swift */; }; @@ -946,6 +950,7 @@ C44067F627E258410045BD4E /* DomainListPhpCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListPhpCell.swift; sourceTree = ""; }; C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListTypeCell.swift; sourceTree = ""; }; C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListTLSCell.swift; sourceTree = ""; }; + C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigFSNotifier.swift; sourceTree = ""; }; C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIHelper.swift; sourceTree = ""; }; C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionPopoverView.swift; sourceTree = ""; }; C4463FCB29804BCB007B93D5 /* RCFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RCFile.swift; sourceTree = ""; }; @@ -1054,7 +1059,7 @@ C4C8900428F0E3D100CE5E97 /* RealFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealFileSystem.swift; sourceTree = ""; }; C4C8900628F0E3EF00CE5E97 /* ActiveFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveFileSystem.swift; sourceTree = ""; }; C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "App+ConfigWatch.swift"; sourceTree = ""; }; - C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpConfigWatcher.swift; sourceTree = ""; }; + C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigWatchManager.swift; sourceTree = ""; }; C4CB250429B28BB800CA4492 /* MainMenuTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenuTest.swift; sourceTree = ""; }; C4CB6E64292C362C002E9027 /* Homebrew.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Homebrew.swift; sourceTree = ""; }; C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = ""; }; @@ -1745,7 +1750,6 @@ C4B5635D276AB09000F12CCB /* VersionExtractor.swift */, C4D3660A29113F20006BD146 /* System.swift */, C4D36614291160A1006BD146 /* WIP.swift */, - C41ADCE72970CCC700120423 /* FSNotifier.swift */, C47DF1AE299D5A3B0007055D /* LoginItemManager.swift */, C49EAA5129B12A5A00AB28FC /* Measurements.swift */, ); @@ -1964,9 +1968,11 @@ C4C8E81D276F5686003AC782 /* Watcher */ = { isa = PBXGroup; children = ( + C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */, + C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */, + C41ADCE72970CCC700120423 /* FSNotifier.swift */, C49EAA5629B1689200AB28FC /* App+BrewWatch.swift */, C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */, - C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */, ); path = Watcher; sourceTree = ""; @@ -2506,8 +2512,9 @@ C4D4CB3729C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */, C46EBC4728DB9644007ACC74 /* RealShell.swift in Sources */, C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */, + C441CC562AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */, C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */, - C4C8E81B276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */, + C4C8E81B276F54E5003AC782 /* ConfigWatchManager.swift in Sources */, C417DC74277614690015E6EE /* Helpers.swift in Sources */, C415D3E82770F692005EF286 /* AppDelegate+InterApp.swift in Sources */, C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */, @@ -2683,7 +2690,7 @@ C471E87828F9BB650021E251 /* TerminalProgressWindowController.swift in Sources */, C471E87928F9BB650021E251 /* ProgressVC.swift in Sources */, C471E87B28F9BB650021E251 /* App+ConfigWatch.swift in Sources */, - C471E87C28F9BB650021E251 /* PhpConfigWatcher.swift in Sources */, + C471E87C28F9BB650021E251 /* ConfigWatchManager.swift in Sources */, C471E87D28F9BB650021E251 /* Preset.swift in Sources */, C471E87E28F9BB650021E251 /* PresetHelper.swift in Sources */, C471E87F28F9BB650021E251 /* WarningView.swift in Sources */, @@ -2728,6 +2735,7 @@ C471E7E828F9BAC20021E251 /* Actions.swift in Sources */, C40D72612A018AE30054A067 /* BrewFormula+UI.swift in Sources */, C471E82528F9BB2E0021E251 /* ComposerWindow.swift in Sources */, + C441CC582AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */, C471E80828F9BAD40021E251 /* PhpExtension.swift in Sources */, C471E7F928F9BACB0021E251 /* PhpSwitcher.swift in Sources */, C471E82A28F9BB330021E251 /* ValetListable.swift in Sources */, @@ -2785,6 +2793,7 @@ C471E89228F9BB8F0021E251 /* Alert.swift in Sources */, C471E89328F9BB8F0021E251 /* Application.swift in Sources */, C471E89428F9BB8F0021E251 /* LocalNotification.swift in Sources */, + C441CC592AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */, C40934A5298EEB2C00D25014 /* CaskFile.swift in Sources */, C471E89528F9BB8F0021E251 /* MenuBarImageGenerator.swift in Sources */, C40D725D2A018ACC0054A067 /* PhpFormulaeStatus.swift in Sources */, @@ -2871,7 +2880,7 @@ C471E8DC28F9BB8F0021E251 /* ProgressVC.swift in Sources */, C490E3BF29BCA376006D2DE6 /* Measurements.swift in Sources */, C471E8DE28F9BB8F0021E251 /* App+ConfigWatch.swift in Sources */, - C471E8DF28F9BB8F0021E251 /* PhpConfigWatcher.swift in Sources */, + C471E8DF28F9BB8F0021E251 /* ConfigWatchManager.swift in Sources */, C4CB250529B28BB800CA4492 /* MainMenuTest.swift in Sources */, C40D72622A018AE30054A067 /* BrewFormula+UI.swift in Sources */, C4B79ECE29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */, @@ -3018,7 +3027,7 @@ C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */, C485707928BF456C00539B36 /* ArrayExtension.swift in Sources */, C4F780CA25D80B75000DBC97 /* HomebrewDecodable.swift in Sources */, - C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */, + C4C8E81C276F54E5003AC782 /* ConfigWatchManager.swift in Sources */, C4F319C927B034A500AFF46F /* Stats.swift in Sources */, C4F30B04278E16BA00755FCE /* HomebrewService.swift in Sources */, 54D9E0B527E4F51E003B9AD9 /* Key.swift in Sources */, @@ -3034,6 +3043,7 @@ C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */, C4B5635F276AB09000F12CCB /* VersionExtractor.swift in Sources */, C463E381284930EE00422731 /* PresetHelper.swift in Sources */, + C441CC572AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */, C46FA98C2822F08F00D78807 /* PhpConfigurationFileTest.swift in Sources */, C4D5576529C77CC5001A44CD /* PhpVersionManagerWindowController.swift in Sources */, C4BF90C127C57C220054E78C /* MainMenu+FixMyValet.swift in Sources */, @@ -3492,7 +3502,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1335; + CURRENT_PROJECT_VERSION = 1336; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3523,7 +3533,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1335; + CURRENT_PROJECT_VERSION = 1336; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3763,7 +3773,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1335; + CURRENT_PROJECT_VERSION = 1336; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3879,7 +3889,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1335; + CURRENT_PROJECT_VERSION = 1336; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3995,7 +4005,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1335; + CURRENT_PROJECT_VERSION = 1336; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -4176,7 +4186,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1335; + CURRENT_PROJECT_VERSION = 1336; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; diff --git a/phpmon/Common/PHP/PhpConfigurationFile.swift b/phpmon/Common/PHP/PhpConfigurationFile.swift index 8ba0dfa..3658615 100644 --- a/phpmon/Common/PHP/PhpConfigurationFile.swift +++ b/phpmon/Common/PHP/PhpConfigurationFile.swift @@ -97,14 +97,14 @@ class PhpConfigurationFile: CreatedFromFile { self.lines[item.lineIndex] = components.joined(separator: "=") // Ensure the watchers aren't tripped up by config changes - PhpConfigWatcher.ignoresModificationsToConfigValues = true + ConfigWatchManager.ignoresModificationsToConfigValues = true // Finally, join the string and save the file atomatically again try self.lines.joined(separator: "\n") .write(toFile: self.filePath, atomically: true, encoding: .utf8) // Ensure watcher behaviour is reverted - PhpConfigWatcher.ignoresModificationsToConfigValues = false + ConfigWatchManager.ignoresModificationsToConfigValues = false // Reload the original file self.reload() diff --git a/phpmon/Domain/App/App.swift b/phpmon/Domain/App/App.swift index 3c89866..52bff0d 100644 --- a/phpmon/Domain/App/App.swift +++ b/phpmon/Domain/App/App.swift @@ -89,9 +89,6 @@ class App { /** The warning manager, responsible for keeping track of warnings. */ var warnings = WarningManager.shared - /** The filesystem watchers, responsible for keeping track of changes to the PHP installation. */ - var watchers: [FSNotifier.Kind: FSNotifier] = [:] - /** Timer that will periodically reload info about the user's PHP installation. */ var timer: Timer? @@ -120,8 +117,12 @@ class App { // MARK: - App Watchers - /** - The `PhpConfigWatcher` is responsible for watching the `.ini` files and the `.conf.d` folder. + /** Individual filesystem watchers, which are, i.e. responsible for watching the Homebrew folders. */ + var watchers: [String: FSNotifier] = [:] + + /** + The `ConfigWatchManager` is responsible for watching the `.ini` files and the `.conf.d` folder. + This manager object can immediately start or stop all watchers (or pause them) all at once. */ - var watcher: PhpConfigWatcher! + var watchManager: ConfigWatchManager! } diff --git a/phpmon/Domain/Watcher/App+BrewWatch.swift b/phpmon/Domain/Watcher/App+BrewWatch.swift index 6986b7b..deda43f 100644 --- a/phpmon/Domain/Watcher/App+BrewWatch.swift +++ b/phpmon/Domain/Watcher/App+BrewWatch.swift @@ -17,13 +17,13 @@ extension App { onChange: { Task { await self.onHomebrewPhpModification() } } ) - App.shared.watchers[.homebrewBinaries] = notifier + App.shared.watchers["homebrewBinaries"] = notifier } public func destroyHomebrewWatchers() { // Removing requires termination and then removing reference - self.watchers[.homebrewBinaries]?.terminate() - self.watchers[.homebrewBinaries] = nil + self.watchers["homebrewBinaries"]?.terminate() + self.watchers["homebrewBinaries"] = nil } public func onHomebrewPhpModification() async { @@ -31,10 +31,13 @@ extension App { Log.info("Something changed in the Homebrew binary directory...") await PhpEnvironments.detectPhpVersions() await MainMenu.shared.refreshActiveInstallation() - // let new = PhpEnvironments.shared.currentInstall?.version.text - // TODO: - // Check if the new and previous version are different - // if so, we can show a notification if needed + // + // TODO: PHP Guard 2.0 + // Check if the new and previous version of PHP are different + // if so, we can show a notification if needed or alert the user + // + // let new = PhpEnvironments.shared.currentInstall?.version.text + // } } diff --git a/phpmon/Domain/Watcher/App+ConfigWatch.swift b/phpmon/Domain/Watcher/App+ConfigWatch.swift index 9588b80..cc2098c 100644 --- a/phpmon/Domain/Watcher/App+ConfigWatch.swift +++ b/phpmon/Domain/Watcher/App+ConfigWatch.swift @@ -10,52 +10,52 @@ import Foundation extension App { - func startWatcher(_ url: URL) { - Log.perf("No watcher currently active...") - self.watcher = PhpConfigWatcher(for: url) + func startWatchManager(_ url: URL) { + Log.perf("Starting config watch manager...") + self.watchManager = ConfigWatchManager(for: url) - self.watcher.didChange = { url in + self.watchManager.didChange = { url in Log.perf("Something has changed in: \(url)") // Check if the watcher has last updated the menu less than 0.75s ago - let distance = self.watcher.lastUpdate?.distance(to: Date().timeIntervalSince1970) + let distance = self.watchManager.lastUpdate?.distance(to: Date().timeIntervalSince1970) if distance == nil || distance != nil && distance! > 0.75 { Log.perf("Refreshing menu...") Task { @MainActor in MainMenu.shared.reloadPhpMonitorMenuInBackground() } - self.watcher.lastUpdate = Date().timeIntervalSince1970 + self.watchManager.lastUpdate = Date().timeIntervalSince1970 } } } func handlePhpConfigWatcher(forceReload: Bool = false) { if ActiveFileSystem.shared is TestableFileSystem { - Log.warn("FS watcher is disabled when using testable filesystem.") + Log.warn("Config watch manager is disabled when using testable filesystem.") return } guard let install = PhpEnvironments.phpInstall else { Log.info("It appears as if no PHP installation is currently active.") - Log.info("The FS watcher will be disabled until a PHP install is active.") + Log.info("The config watch manager be disabled until a PHP install is active.") return } let url = URL(fileURLWithPath: "\(Paths.etcPath)/php/\(install.version.short)") - // Check whether the watcher exists and schedule on the main thread + // Check whether the manager exists and schedule on the main thread // if we don't consistently do this, the app will create duplicate watchers - // due to timing issues, which creates retain cycles. + // due to timing issues, which creates retain cycles Task { @MainActor in // Watcher needs to be created - if self.watcher == nil { - self.startWatcher(url) + if self.watchManager == nil { + self.startWatchManager(url) } // Watcher needs to be updated - if self.watcher.url != url || forceReload { - self.watcher.disable() - self.watcher = nil + if self.watchManager.url != url || forceReload { + self.watchManager.disable() + self.watchManager = nil Log.perf("Watcher has stopped watching files. Starting new one...") - self.startWatcher(url) + self.startWatchManager(url) } } } diff --git a/phpmon/Domain/Watcher/ConfigFSNotifier.swift b/phpmon/Domain/Watcher/ConfigFSNotifier.swift new file mode 100644 index 0000000..786ab47 --- /dev/null +++ b/phpmon/Domain/Watcher/ConfigFSNotifier.swift @@ -0,0 +1,77 @@ +// +// ConfigFSNotifier.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 24/10/2023. +// Copyright © 2023 Nico Verbruggen. All rights reserved. +// + +import Foundation + +class ConfigFSNotifier { + + enum Behaviour { + case reloadsMenu + case reloadsWatchers + } + + private var parent: ConfigWatchManager! + + private var monitoredFolderFileDescriptor: CInt = -1 + + private var folderMonitorSource: DispatchSourceFileSystemObject? + + let url: URL + + init( + for url: URL, + eventMask: DispatchSource.FileSystemEvent, + parent: ConfigWatchManager, + behaviour: ConfigFSNotifier.Behaviour = .reloadsMenu + ) { + self.url = url + self.parent = parent + self.startMonitoring(eventMask, behaviour: behaviour) + } + + func startMonitoring( + _ eventMask: DispatchSource.FileSystemEvent, + behaviour: ConfigFSNotifier.Behaviour + ) { + guard folderMonitorSource == nil && monitoredFolderFileDescriptor == -1 else { + return + } + + monitoredFolderFileDescriptor = open(url.path, O_EVTONLY) + folderMonitorSource = DispatchSource.makeFileSystemObjectSource( + fileDescriptor: monitoredFolderFileDescriptor, + eventMask: eventMask, + queue: parent.folderMonitorQueue + ) + + folderMonitorSource?.setEventHandler { [weak self] in + if behaviour == .reloadsWatchers + && !ConfigWatchManager.ignoresModificationsToConfigValues { + // Reload all configuration watchers + return App.shared.handlePhpConfigWatcher(forceReload: true) + } + + + self?.parent.didChange?(self!.url) + } + + folderMonitorSource?.setCancelHandler { [weak self] in + guard let self = self else { return } + close(self.monitoredFolderFileDescriptor) + self.monitoredFolderFileDescriptor = -1 + self.folderMonitorSource = nil + } + + folderMonitorSource?.resume() + } + + func stopMonitoring() { + folderMonitorSource?.cancel() + self.parent = nil + } +} diff --git a/phpmon/Domain/Watcher/ConfigWatchManager.swift b/phpmon/Domain/Watcher/ConfigWatchManager.swift new file mode 100644 index 0000000..7b780ab --- /dev/null +++ b/phpmon/Domain/Watcher/ConfigWatchManager.swift @@ -0,0 +1,82 @@ +// +// ConfigWatchManager.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 30/03/2021. +// Copyright © 2023 Nico Verbruggen. All rights reserved. +// + +import Foundation + +class ConfigWatchManager { + + static var ignoresModificationsToConfigValues: Bool = false + + let folderMonitorQueue = DispatchQueue(label: "FolderMonitorQueue", attributes: .concurrent) + + let url: URL + var didChange: ((URL) -> Void)? + var lastUpdate: TimeInterval? + + var watchers: [ConfigFSNotifier] = [] + + init(for url: URL) { + if FileSystem is TestableFileSystem { + fatalError(""" + PhpConfigWatcher is not compatible with testable FS!" + You are not allowed to instantiate these while using a testable FS. + """) + } + + self.url = url + + // Add a watcher for php.ini + self.addWatcher(for: self.url.appendingPathComponent("php.ini"), eventMask: .write) + + // Add a watcher for conf.d (in case a new file is added or a file is deleted) + // This watcher, when triggered, will restart all watchers + self.addWatcher(for: self.url.appendingPathComponent("conf.d"), eventMask: .all, behaviour: .reloadsWatchers) + + // Scan the conf.d folder for .ini files, and add a watcher for each file + let filePaths = FileManager.default.enumerator( + atPath: self.url.appendingPathComponent("conf.d").path + )?.allObjects as! [String] + + // Loop over the .ini files that we discovered + filePaths.filter { $0.contains(".ini") }.forEach { (file) in + // Add a watcher for each file we have discovered + self.addWatcher(for: self.url.appendingPathComponent("conf.d/\(file)"), eventMask: .write) + } + + Log.perf("A watcher exists for the following config paths:") + Log.perf(self.watchers.map({ watcher in + return watcher.url.relativePath + })) + } + + func addWatcher( + for url: URL, + eventMask: DispatchSource.FileSystemEvent, + behaviour: ConfigFSNotifier.Behaviour = .reloadsMenu + ) { + if !FileSystem.anyExists(url.path) { + Log.warn("No watcher was created for \(url.path) because the requested file does not exist.") + return + } + + let watcher = ConfigFSNotifier(for: url, eventMask: eventMask, parent: self, behaviour: behaviour) + self.watchers.append(watcher) + } + + func disable() { + Log.perf("Turning off all individual existing watchers...") + self.watchers.forEach { (watcher) in + watcher.stopMonitoring() + } + } + + deinit { + Log.perf("deinit: \(String(describing: self)).\(#function)") + } + +} diff --git a/phpmon/Common/Helpers/FSNotifier.swift b/phpmon/Domain/Watcher/FSNotifier.swift similarity index 95% rename from phpmon/Common/Helpers/FSNotifier.swift rename to phpmon/Domain/Watcher/FSNotifier.swift index 349d78e..01332c8 100644 --- a/phpmon/Common/Helpers/FSNotifier.swift +++ b/phpmon/Domain/Watcher/FSNotifier.swift @@ -6,12 +6,9 @@ // Copyright © 2023 Nico Verbruggen. All rights reserved. // -import Cocoa +import Foundation class FSNotifier { - enum Kind { - case homebrewLocks, homebrewBinaries - } public static var shared: FSNotifier! = nil @@ -66,4 +63,5 @@ class FSNotifier { deinit { Log.perf("FSNotifier for \(self.url) will be deinitialized.") } + } diff --git a/phpmon/Domain/Watcher/PhpConfigWatcher.swift b/phpmon/Domain/Watcher/PhpConfigWatcher.swift deleted file mode 100644 index 9a585f5..0000000 --- a/phpmon/Domain/Watcher/PhpConfigWatcher.swift +++ /dev/null @@ -1,155 +0,0 @@ -// -// FolderWatcher.swift -// PHP Monitor -// -// Created by Nico Verbruggen on 30/03/2021. -// Copyright © 2023 Nico Verbruggen. All rights reserved. -// - -import Foundation - -class PhpConfigWatcher { - - static var ignoresModificationsToConfigValues: Bool = false - - let folderMonitorQueue = DispatchQueue(label: "FolderMonitorQueue", attributes: .concurrent) - - let url: URL - - var didChange: ((URL) -> Void)? - - var lastUpdate: TimeInterval? - - var watchers: [FSWatcher] = [] - - init(for url: URL) { - if FileSystem is TestableFileSystem { - fatalError(""" - PhpConfigWatcher is not compatible with testable FS!" - You are not allowed to instantiate these while using a testable FS. - """) - } - - self.url = url - - // Add a watcher for php.ini - self.addWatcher(for: self.url.appendingPathComponent("php.ini"), eventMask: .write) - - // Add a watcher for conf.d (in case a new file is added or a file is deleted) - // This watcher, when triggered, will restart all watchers - self.addWatcher(for: self.url.appendingPathComponent("conf.d"), eventMask: .all, behaviour: .reloadsWatchers) - - // Scan the conf.d folder for .ini files, and add a watcher for each file - let enumerator = FileManager.default.enumerator(atPath: self.url.appendingPathComponent("conf.d").path) - let filePaths = enumerator?.allObjects as! [String] - - // Loop over the .ini files that we discovered - filePaths.filter { $0.contains(".ini") }.forEach { (file) in - // Add a watcher for each file we have discovered - self.addWatcher(for: self.url.appendingPathComponent("conf.d/\(file)"), eventMask: .write) - } - - Log.perf("A watcher exists for the following config paths:") - Log.perf(self.watchers.map({ watcher in - return watcher.url.relativePath - })) - } - - func addWatcher( - for url: URL, - eventMask: DispatchSource.FileSystemEvent, - behaviour: FSWatcherBehaviour = .reloadsMenu - ) { - if !FileSystem.anyExists(url.path) { - Log.warn("No watcher was created for \(url.path) because the requested file does not exist.") - return - } - - let watcher = FSWatcher(for: url, eventMask: eventMask, parent: self, behaviour: behaviour) - self.watchers.append(watcher) - } - - func disable() { - Log.perf("Turning off all individual existing watchers...") - self.watchers.forEach { (watcher) in - watcher.stopMonitoring() - } - } - - deinit { - Log.perf("deinit: \(String(describing: self)).\(#function)") - } - -} - -enum FSWatcherBehaviour { - case reloadsMenu - case reloadsWatchers -} - -class FSWatcher { - - private var parent: PhpConfigWatcher! - - private var monitoredFolderFileDescriptor: CInt = -1 - - private var folderMonitorSource: DispatchSourceFileSystemObject? - - let url: URL - - init( - for url: URL, - eventMask: DispatchSource.FileSystemEvent, - parent: PhpConfigWatcher, - behaviour: FSWatcherBehaviour = .reloadsMenu - ) { - self.url = url - self.parent = parent - self.startMonitoring(eventMask, behaviour: behaviour) - } - - func startMonitoring( - _ eventMask: DispatchSource.FileSystemEvent, - behaviour: FSWatcherBehaviour - ) { - guard folderMonitorSource == nil && monitoredFolderFileDescriptor == -1 else { - return - } - - // Open the file or folder referenced by URL for monitoring only. - monitoredFolderFileDescriptor = open(url.path, O_EVTONLY) - folderMonitorSource = DispatchSource.makeFileSystemObjectSource( - fileDescriptor: monitoredFolderFileDescriptor, - eventMask: eventMask, - queue: parent.folderMonitorQueue - ) - - // Define the block to call when a file change is detected. - folderMonitorSource?.setEventHandler { [weak self] in - if behaviour == .reloadsWatchers - && !PhpConfigWatcher.ignoresModificationsToConfigValues { - // Reload all configuration watchers - return App.shared.handlePhpConfigWatcher(forceReload: true) - } - - // The default behaviour is to reload the menu - self?.parent.didChange?(self!.url) - } - - // Define a cancel handler to ensure the directory is closed when the source is cancelled. - folderMonitorSource?.setCancelHandler { [weak self] in - guard let self = self else { return } - close(self.monitoredFolderFileDescriptor) - self.monitoredFolderFileDescriptor = -1 - self.folderMonitorSource = nil - } - - // Start monitoring the directory via the source. - folderMonitorSource?.resume() - } - - func stopMonitoring() { - folderMonitorSource?.cancel() - self.parent = nil - } -} From 1ae7a20870de67cda024262c94942e5ba2f2c05b Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Thu, 26 Oct 2023 17:14:23 +0200 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=91=8C=20Adjust=20error=20message?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- phpmon/Domain/Watcher/ConfigWatchManager.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpmon/Domain/Watcher/ConfigWatchManager.swift b/phpmon/Domain/Watcher/ConfigWatchManager.swift index 7b780ab..91d6a6e 100644 --- a/phpmon/Domain/Watcher/ConfigWatchManager.swift +++ b/phpmon/Domain/Watcher/ConfigWatchManager.swift @@ -23,8 +23,8 @@ class ConfigWatchManager { init(for url: URL) { if FileSystem is TestableFileSystem { fatalError(""" - PhpConfigWatcher is not compatible with testable FS!" - You are not allowed to instantiate these while using a testable FS. + ConfigWatchManager is currently incompatible with a testable filesystem!" + You are not allowed to instantiate these while using a testable filesystem. """) } From e05300b25b5f9023bf95104496f49c9cdb0ab609 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Thu, 26 Oct 2023 18:55:21 +0200 Subject: [PATCH 11/12] =?UTF-8?q?=F0=9F=94=A7=20Bump=20build?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index f45a157..9366541 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -3502,7 +3502,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1336; + CURRENT_PROJECT_VERSION = 1340; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3533,7 +3533,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1336; + CURRENT_PROJECT_VERSION = 1340; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3773,7 +3773,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1336; + CURRENT_PROJECT_VERSION = 1340; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; @@ -3889,7 +3889,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1336; + CURRENT_PROJECT_VERSION = 1340; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -4005,7 +4005,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1336; + CURRENT_PROJECT_VERSION = 1340; DEAD_CODE_STRIPPING = YES; DEBUG = YES; DEVELOPMENT_TEAM = 8M54J5J787; @@ -4186,7 +4186,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1336; + CURRENT_PROJECT_VERSION = 1340; DEAD_CODE_STRIPPING = YES; DEBUG = NO; DEVELOPMENT_TEAM = 8M54J5J787; From 91bc347e57fa10a3ac7fee99029150be49df1e20 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Thu, 26 Oct 2023 19:31:55 +0200 Subject: [PATCH 12/12] =?UTF-8?q?=F0=9F=90=9B=20Fix=20tests,=20fix=20issue?= =?UTF-8?q?=20with=20window=20to=20front?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 18 ++++ phpmon/Domain/App/Base.lproj/Main.storyboard | 92 +++++++++---------- phpmon/Domain/Notice/BetterAlert.swift | 1 + .../Modules/Domain List/UI/DomainListVC.swift | 1 + .../UI/ConfigManagerWindowController.swift | 2 +- .../UI/PhpDoctorWindowController.swift | 1 + .../PhpVersionManagerWindowController.swift | 2 + tests/ui/DomainsListTest.swift | 18 ++-- tests/ui/MainMenuTest.swift | 2 + 9 files changed, 81 insertions(+), 56 deletions(-) diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 9366541..dbd1635 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -232,6 +232,15 @@ C45E2A77291992DA005C7CFD /* FeatureTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E2A76291992DA005C7CFD /* FeatureTestCase.swift */; }; C45E76142854A65300B4FE0C /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; }; C45E76152854A65300B4FE0C /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; }; + C4611E5A2AEAD2E20010BE24 /* ConfigManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */; }; + C4611E5B2AEAD2E30010BE24 /* ConfigManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */; }; + C4611E5C2AEAD2E30010BE24 /* ConfigManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */; }; + C4611E5D2AEAD2FA0010BE24 /* ConfigManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44DFA7B2A67043000B98ED5 /* ConfigManagerView.swift */; }; + C4611E5E2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44DFA7B2A67043000B98ED5 /* ConfigManagerView.swift */; }; + C4611E5F2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44DFA7B2A67043000B98ED5 /* ConfigManagerView.swift */; }; + C4611E602AEAD3100010BE24 /* ByteLimitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5857B2A7038DB00DDBB63 /* ByteLimitView.swift */; }; + C4611E612AEAD3110010BE24 /* ByteLimitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5857B2A7038DB00DDBB63 /* ByteLimitView.swift */; }; + C4611E622AEAD3110010BE24 /* ByteLimitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5857B2A7038DB00DDBB63 /* ByteLimitView.swift */; }; C463E380284930EE00422731 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; }; C463E381284930EE00422731 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; }; C464ADAC275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAB275A7A3F003FCD53 /* DomainListWindowController.swift */; }; @@ -2644,8 +2653,10 @@ C4B79EBE29CA38DB00A483EE /* BrewCommand.swift in Sources */, C47DF1B1299D5A3B0007055D /* LoginItemManager.swift in Sources */, C471E85928F9BB650021E251 /* DomainListPhpCell.swift in Sources */, + C4611E5B2AEAD2E30010BE24 /* ConfigManagerWindowController.swift in Sources */, C471E85A28F9BB650021E251 /* DomainListTypeCell.swift in Sources */, C471E85B28F9BB650021E251 /* DomainListKindCell.swift in Sources */, + C4611E5E2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */, C4BF56AD2949381100379603 /* FakeValetInteractor.swift in Sources */, C471E85C28F9BB650021E251 /* DomainListWindowController.swift in Sources */, C471E85D28F9BB650021E251 /* DomainListVC.swift in Sources */, @@ -2764,6 +2775,7 @@ C471E7FD28F9BACE0021E251 /* HomebrewService.swift in Sources */, C471E7E428F9BAC20021E251 /* Helpers.swift in Sources */, C4CB6E67292C362C002E9027 /* Homebrew.swift in Sources */, + C4611E602AEAD3100010BE24 /* ByteLimitView.swift in Sources */, C489E0BD2A220A4200323F5E /* FakeBrewFormulaeHandler.swift in Sources */, C45E2A77291992DA005C7CFD /* FeatureTestCase.swift in Sources */, C471E82028F9BB290021E251 /* NginxConfigurationFile.swift in Sources */, @@ -2875,6 +2887,7 @@ C471E8D528F9BB8F0021E251 /* CheckboxPreferenceView.swift in Sources */, C471E8D728F9BB8F0021E251 /* SelectPreferenceView.swift in Sources */, C471E8D928F9BB8F0021E251 /* HotkeyPreferenceView.swift in Sources */, + C4611E5D2AEAD2FA0010BE24 /* ConfigManagerView.swift in Sources */, C471E8DA28F9BB8F0021E251 /* Keys.swift in Sources */, C471E8DB28F9BB8F0021E251 /* TerminalProgressWindowController.swift in Sources */, C471E8DC28F9BB8F0021E251 /* ProgressVC.swift in Sources */, @@ -2917,6 +2930,7 @@ C471E7F628F9BAC80021E251 /* PhpHelper.swift in Sources */, C471E7EE28F9BAC30021E251 /* Constants.swift in Sources */, C40934A0298EE8E900D25014 /* AppUpdater.swift in Sources */, + C4611E5A2AEAD2E20010BE24 /* ConfigManagerWindowController.swift in Sources */, C471E80E28F9BAE80021E251 /* DateExtension.swift in Sources */, C490E3BA29BCA368006D2DE6 /* App+BrewWatch.swift in Sources */, C471E7D028F9BA630021E251 /* FileSystemProtocol.swift in Sources */, @@ -2964,6 +2978,7 @@ C471E7EB28F9BAC30021E251 /* Helpers.swift in Sources */, C4CB6E68292C362C002E9027 /* Homebrew.swift in Sources */, C4181F1128FAF9330042EA28 /* UITestCase.swift in Sources */, + C4611E622AEAD3110010BE24 /* ByteLimitView.swift in Sources */, C4AFC4B129C4F32F00BF4E0D /* BrewFormula.swift in Sources */, C471E81F28F9BB290021E251 /* NginxConfigurationFile.swift in Sources */, C471E7BF28F9B90F0021E251 /* StartupTest.swift in Sources */, @@ -3051,6 +3066,7 @@ C4F2E4382752F08D0020E974 /* BrewDiagnostics.swift in Sources */, C485707428BF454E00539B36 /* ServicesView.swift in Sources */, C4B79EC729CA474200A483EE /* FakeCommand.swift in Sources */, + C4611E5F2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */, C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */, C456A0C72AA614BD0080144F /* PhpPreference.swift in Sources */, C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, @@ -3091,6 +3107,7 @@ C4E49DEE28F764A00026AC4E /* TestableCommand.swift in Sources */, C4AF9F78275447F100D44ED0 /* ValetConfigurationTest.swift in Sources */, C490E3B529BC9FEA006D2DE6 /* ProgressWindowView.swift in Sources */, + C4611E612AEAD3110010BE24 /* ByteLimitView.swift in Sources */, C40175B92903108900763A68 /* ValetInteractor.swift in Sources */, C4CE3BBC27B324250086CA49 /* ComposerWindow.swift in Sources */, C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */, @@ -3119,6 +3136,7 @@ C4D936CA27E3EB6100BD69FE /* PhpHelper.swift in Sources */, C4D36611291140BE006BD146 /* TestableFileSystemTest.swift in Sources */, C45B91542956123A00F4EC78 /* FakeServicesManager.swift in Sources */, + C4611E5C2AEAD2E30010BE24 /* ConfigManagerWindowController.swift in Sources */, C4E2E84B28FC1E70003B070C /* DataExtension.swift in Sources */, C449B4F127EE7FC200C47E8A /* DomainListNameCell.swift in Sources */, C4F780BA25D80B62000DBC97 /* AppDelegate.swift in Sources */, diff --git a/phpmon/Domain/App/Base.lproj/Main.storyboard b/phpmon/Domain/App/Base.lproj/Main.storyboard index 16495fd..9d0adbe 100644 --- a/phpmon/Domain/App/Base.lproj/Main.storyboard +++ b/phpmon/Domain/App/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -429,7 +429,7 @@ - + @@ -521,9 +521,6 @@ - + @@ -710,7 +710,7 @@ Gw - + @@ -728,7 +728,7 @@ Gw - + @@ -743,7 +743,7 @@ Gw - + @@ -751,7 +751,7 @@ Gw -