diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 96961a9..7dbc8cb 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -92,6 +92,10 @@ C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0C9525CC80B100CC7490 /* HeaderView.swift */; }; C48D0C9A25CC888B00CC7490 /* HeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C48D0C9925CC888B00CC7490 /* HeaderView.xib */; }; C48D0CA325CC992000CC7490 /* StatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0CA225CC992000CC7490 /* StatsView.swift */; }; + C48D6C70279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; }; + C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; }; + C48D6C72279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; }; + C48D6C75279CD3E400F26D7E /* PhpVersionNumberTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */; }; C4998F0626175E7200B2526E /* HotKey in Frameworks */ = {isa = PBXBuildFile; productRef = C4998F0526175E7200B2526E /* HotKey */; }; C4998F0A2617633900B2526E /* PrefsWC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4998F092617633900B2526E /* PrefsWC.swift */; }; C4998F0B2617633900B2526E /* PrefsWC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4998F092617633900B2526E /* PrefsWC.swift */; }; @@ -257,6 +261,8 @@ C48D0C9525CC80B100CC7490 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; C48D0C9925CC888B00CC7490 /* HeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HeaderView.xib; sourceTree = ""; }; C48D0CA225CC992000CC7490 /* StatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsView.swift; sourceTree = ""; }; + C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpVersionNumber.swift; sourceTree = ""; }; + C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpVersionNumberTest.swift; sourceTree = ""; }; C4998F092617633900B2526E /* PrefsWC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsWC.swift; sourceTree = ""; }; C4ACA38E25C754C100060C66 /* PhpExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpExtension.swift; sourceTree = ""; }; C4AF9F70275445FF00D44ED0 /* valet-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "valet-config.json"; sourceTree = ""; }; @@ -343,9 +349,9 @@ 54B20EDF263AA22C00D3250E /* PHP */ = { isa = PBXGroup; children = ( + C48D6C6E279CD29C00F26D7E /* PHP Version */, C4D9ADC2277610E4007277F4 /* Switcher */, C4F30B01278E169B00755FCE /* Homebrew */, - C40C7F1D2772136000DDDCDC /* PhpEnv.swift */, C41C1B4A22B019FF00E7CF16 /* ActivePhpInstallation.swift */, C4F2E4392752F7D00020E974 /* PhpInstallation.swift */, C4ACA38E25C754C100060C66 /* PhpExtension.swift */, @@ -523,6 +529,15 @@ path = Helpers; sourceTree = ""; }; + C48D6C6E279CD29C00F26D7E /* PHP Version */ = { + isa = PBXGroup; + children = ( + C40C7F1D2772136000DDDCDC /* PhpEnv.swift */, + C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */, + ); + path = "PHP Version"; + sourceTree = ""; + }; C4AF9F6A275445C900D44ED0 /* Valet */ = { isa = PBXGroup; children = ( @@ -643,6 +658,7 @@ C4F780AD25D80B37000DBC97 /* ExtensionParserTest.swift */, C43A8A2325D9D20D00591B77 /* BrewJsonParserTest.swift */, C4FBFC512616485F00CDB8E1 /* PhpVersionDetectionTest.swift */, + C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */, C43A8A1925D9CD1000591B77 /* Utility.swift */, C4AF9F76275447F100D44ED0 /* ValetConfigParserTest.swift */, C4AF9F7C275454A900D44ED0 /* ValetTest.swift */, @@ -818,6 +834,7 @@ C40C7F2327721F8200DDDCDC /* ActivePhpInstallation.swift in Sources */, C4B585462770FE3900DA4FBE /* Command.swift in Sources */, C4D9ADCA277611A0007277F4 /* InternalSwitcher.swift in Sources */, + C48D6C72279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */, C40C7F2527721F9800DDDCDC /* HomebrewPackage.swift in Sources */, C417DC76277614690015E6EE /* Helpers.swift in Sources */, C40C7F3227722E8D00DDDCDC /* Logger.swift in Sources */, @@ -833,6 +850,7 @@ files = ( C4ACA38F25C754C100060C66 /* PhpExtension.swift in Sources */, C4D8016622B1584700C6DA1B /* Startup.swift in Sources */, + C48D6C70279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */, C4B585412770FE3900DA4FBE /* Shell.swift in Sources */, C4998F0A2617633900B2526E /* PrefsWC.swift in Sources */, C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */, @@ -928,6 +946,7 @@ C4F780AE25D80B37000DBC97 /* ExtensionParserTest.swift in Sources */, C4F780C725D80B75000DBC97 /* StatusMenu.swift in Sources */, C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, + C48D6C75279CD3E400F26D7E /* PhpVersionNumberTest.swift in Sources */, C43603A1275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */, C42759682627662800093CAE /* NSMenuExtension.swift in Sources */, C4B97B76275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */, @@ -958,6 +977,7 @@ C4B585452770FE3900DA4FBE /* Command.swift in Sources */, C4F780C525D80B75000DBC97 /* MenuBarImageGenerator.swift in Sources */, C4F780B725D80B5D000DBC97 /* App.swift in Sources */, + C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */, C4F780C925D80B75000DBC97 /* StringExtension.swift in Sources */, C4B5853F2770FE3900DA4FBE /* Paths.swift in Sources */, C481F79A26164A7C004FBCFF /* Preferences.swift in Sources */, diff --git a/phpmon-common/PHP/PhpEnv.swift b/phpmon-common/PHP/PHP Version/PhpEnv.swift similarity index 95% rename from phpmon-common/PHP/PhpEnv.swift rename to phpmon-common/PHP/PHP Version/PhpEnv.swift index c5dcb55..8c5d1d7 100644 --- a/phpmon-common/PHP/PhpEnv.swift +++ b/phpmon-common/PHP/PHP Version/PhpEnv.swift @@ -149,4 +149,10 @@ class PhpEnv { return output } + + public func validVersions(for constraint: String) -> [PhpVersionNumber] { + return PhpVersionNumberCollection + .make(from: self.availablePhpVersions) + .matching(constraint: constraint) + } } diff --git a/phpmon-common/PHP/PHP Version/PhpVersionNumber.swift b/phpmon-common/PHP/PHP Version/PhpVersionNumber.swift new file mode 100644 index 0000000..356f0bb --- /dev/null +++ b/phpmon-common/PHP/PHP Version/PhpVersionNumber.swift @@ -0,0 +1,141 @@ +// +// PhpVersionNumber.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 23/01/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Foundation + +public struct PhpVersionNumberCollection: Equatable { + let versions: [PhpVersionNumber] + + public static func make(from versions: [String]) -> Self { + return PhpVersionNumberCollection( + versions: versions.map { PhpVersionNumber.make(from: $0)! } + ) + } + + public var first: PhpVersionNumber? { + return self.versions.first + } + + public var all: [PhpVersionNumber] { + return self.versions + } + + /** + Checks if any versions of PHP are valid for the constraint provided. + Due to the complexity of evaluating these, a important test is maintained. + More information on these constraints can be found here: + https://getcomposer.org/doc/articles/versions.md#writing-version-constraints + + - Parameter constraint: The full constraint as a string (e.g. "^7.0") + - Parameter strict: Whether the minor version check is strict. See more below. + + The strict mode does not matter if a patch version is provided for all versions in the collection. + + Strict mode assumes that any PHP version lacking precise patch information, e.g. inferred + from Homebrew corresponds to the .0 patch version of that version. The default, which is imprecise, + assumes that the patch version is .999, which means that in all cases the patch version check is + always going to pass. + + **STRICT MODE (= patch precision on)** + + Given versions 8.0.? and 8.1.?, but the requirement is ^8.0.1, in strict mode only 8.1.? will + be considered valid (8.0 translates to 8.0.0 and as such is older than 8.0.1, 8.1.0 is OK). + When checking against actual PHP versions installed by the user, use strict mode. + + **NON-STRICT MODE (= patch precision off)** + + Given versions 8.0.? and 8.1.?, but the requirement is ^8.0.1, in non-strict mode version 8.0 + is assumed to be equal to version 8.0.999, which is actually fine if 8.0.1 is the required version. + In non-strict mode, the patch version is ignored for regular version checks (no caret / tilde). + If checking compatibility with general Homebrew versions of PHP, do NOT use strict mode, since + the patch version there is not used. (The formula php@8.0 suffices for ^8.0.1.) + */ + public func matching(constraint: String, strict: Bool = false) -> [PhpVersionNumber] { + if let version = PhpVersionNumber.make(from: constraint, type: .versionOnly) { + // Strict constraint (e.g. "7.0") -> returns specific version + return self.versions.filter { + $0.major == version.major + && $0.minor == version.minor + && (strict ? $0.patch(strict, version) == version.patch(strict) : true) + } + } + + if let version = PhpVersionNumber.make(from: constraint, type: .caretVersionRange) { + // Caret range means that the major version is never higher but minor version can be higher + // ^7.2 will be compatible with all versions between 7.2 and 8.0 + return self.versions.filter { + $0.major == version.major && + ( + // Either the minor version is the same and the patch is higher or equal + $0.minor == version.minor && $0.patch(strict) >= version.patch(strict, $0) + // or the minor version number has been bumped + || $0.minor > version.minor + ) + } + } + + if let version = PhpVersionNumber.make(from: constraint, type: .tildeVersionRange) { + // Tilde range means that most specific digit is used as the basis. + if version.patch != nil { + // If a patch is provided then the minor version cannot be bumped. + return self.versions.filter { + $0.major == version.major && $0.minor == version.minor + && $0.patch(strict, version) >= version.patch! + } + } else { + // If a patch is not provided then the major version cannot be bumped. + return self.versions.filter { + $0.major == version.major && $0.minor >= version.minor + } + } + } + + return [] + } +} + +public struct PhpVersionNumber: Equatable { + let major: Int + let minor: Int + let patch: Int? + + public func patch(_ strictFallback: Bool, _ constraint: PhpVersionNumber? = nil) -> Int { + return patch ?? (strictFallback ? 0 : constraint?.patch ?? 999) + } + + public var homebrewVersion: String { + return "\(major).\(minor)" + } + + public enum MatchType: String { + case versionOnly = #"^(?\d+).(?\d+).?(?\d+)?\z"# + case caretVersionRange = #"^\^(?\d+).(?\d+).?(?\d+)?\z"# + case tildeVersionRange = #"^~(?\d+).(?\d+).?(?\d+)?\z"# + } + + public static func make(from versionString: String, type: MatchType = .versionOnly) -> Self? { + let regex = try! NSRegularExpression(pattern: type.rawValue, options: []) + let match = regex.matches(in: versionString, options: [], range: NSMakeRange(0, versionString.count)).first + + if match != nil { + let major = Int( + versionString[Range(match!.range(withName: "major"), in: versionString)!] + )! + let minor = Int( + versionString[Range(match!.range(withName: "minor"), in: versionString)!] + )! + var patch: Int? = nil + if let minorRange = Range(match!.range(withName: "patch"), in: versionString) { + patch = Int(versionString[minorRange]) + } + return Self(major: major, minor: minor, patch: patch) + } + + return nil + } +} diff --git a/phpmon-common/PHP/PhpInstallation.swift b/phpmon-common/PHP/PhpInstallation.swift index 02577e2..4ecc010 100644 --- a/phpmon-common/PHP/PhpInstallation.swift +++ b/phpmon-common/PHP/PhpInstallation.swift @@ -10,20 +10,26 @@ import Foundation class PhpInstallation { - var longVersion: String + var longVersion: PhpVersionNumber /** In order to determine details about a PHP installation, we’ll simply run `php-config --version` in the relevant directory. */ init(_ version: String) { + let phpConfigExecutablePath = "\(Paths.optPath)/php@\(version)/bin/php-config" - self.longVersion = version + self.longVersion = PhpVersionNumber.make(from: version)! + if Shell.fileExists(phpConfigExecutablePath) { - self.longVersion = Command.execute( + let longVersionString = Command.execute( path: phpConfigExecutablePath, arguments: ["--version"] - ) + ).trimmingCharacters(in: .whitespacesAndNewlines) + + self.longVersion = PhpVersionNumber.make( + from: String(longVersionString.split(separator: "-")[0]) + )! } } diff --git a/phpmon-tests/PhpVersionDetectionTest.swift b/phpmon-tests/PhpVersionDetectionTest.swift index 8585680..fedd72d 100644 --- a/phpmon-tests/PhpVersionDetectionTest.swift +++ b/phpmon-tests/PhpVersionDetectionTest.swift @@ -26,5 +26,4 @@ class PhpVersionDetectionTest: XCTestCase { XCTAssertEqual(outcome, ["8.0", "7.0", "5.6"]) } - } diff --git a/phpmon-tests/PhpVersionNumberTest.swift b/phpmon-tests/PhpVersionNumberTest.swift new file mode 100644 index 0000000..dc9f1cb --- /dev/null +++ b/phpmon-tests/PhpVersionNumberTest.swift @@ -0,0 +1,194 @@ +// +// PhpVersionNumberTest.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 23/01/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import XCTest + +class PhpVersionNumberTest: XCTestCase { + + func testCanDeconstructPhpVersion() throws { + XCTAssertEqual( + PhpVersionNumber.make(from: "8.0.11"), + PhpVersionNumber(major: 8, minor: 0, patch: 11) + ) + XCTAssertEqual( + PhpVersionNumber.make(from: "7.4.2"), + PhpVersionNumber(major: 7, minor: 4, patch: 2) + ) + XCTAssertEqual( + PhpVersionNumber.make(from: "7.4"), + PhpVersionNumber(major: 7, minor: 4, patch: nil) + ) + XCTAssertEqual( + PhpVersionNumber.make(from: "7"), + nil + ) + } + + func testCanCheckFixedConstraints() throws { + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]) + .matching(constraint: "7.0"), + PhpVersionNumberCollection + .make(from: ["7.0"]).all + ) + + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4.3", "7.3.3", "7.2.3", "7.1.3", "7.0.3"]) + .matching(constraint: "7.0.3"), + PhpVersionNumberCollection + .make(from: ["7.0.3"]).all + ) + + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]) + .matching(constraint: "7.0.3", strict: false), + PhpVersionNumberCollection + .make(from: ["7.0"]).all + ) + + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]) + .matching(constraint: "7.0.3", strict: true), + PhpVersionNumberCollection + .make(from: []).all + ) + } + + func testCanCheckCaretConstraints() throws { + // 1. Imprecise checks + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]) + .matching(constraint: "^7.0", strict: true), + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]).all + ) + + // 2. Imprecise check with precise constraint (lenient AKA not strict) + // These versions are interpreted as 7.4.999, 7.3.999, 7.2.999, etc. + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]) + .matching(constraint: "^7.0.1", strict: false), + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]).all + ) + + // 3. Imprecise check with precise constraint (strict mode) + // These versions are interpreted as 7.4.0, 7.3.0, 7.2.0, etc. + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]) + .matching(constraint: "^7.0.1", strict: true), + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1"]).all + ) + + // 4. Precise members and constraint all around + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]) + .matching(constraint: "^7.0.1", strict: true), + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]).all + ) + + // 5. Precise members but imprecise constraint (strict mode) + // In strict mode the constraint's patch version is assumed to be 0 + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]) + .matching(constraint: "^7.0", strict: true), + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]).all + ) + + // 6. Precise members but imprecise constraint (lenient mode) + // In lenient mode the constraint's patch version is assumed to be equal + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]) + .matching(constraint: "^7.0", strict: false), + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]).all + ) + } + + func testCanCheckTildeConstraints() throws { + // 1. Imprecise checks + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]) + .matching(constraint: "~7.0", strict: true), + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]).all + ) + + // 2. Imprecise check with precise constraint (lenient AKA not strict) + // These versions are interpreted as 7.4.999, 7.3.999, 7.2.999, etc. + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]) + .matching(constraint: "~7.0.1", strict: false), + // One result because 7.0.1 to 7.0.x is expected. + // 7.0.999 (assumed due to no strictness) is valid. + // 7.1.0 and up are not valid (minor version is too high). + PhpVersionNumberCollection + .make(from: ["7.0"]).all + ) + + // 3. Imprecise check with precise constraint (strict mode) + // These versions are interpreted as 7.4.0, 7.3.0, 7.2.0, etc. + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]) + .matching(constraint: "~7.0.1", strict: true), + // No results because 7.0.1 to 7.0.x is expected. + // 7.0.0 (assumed due to strictness) is not valid. + // 7.1.0 and up are also not valid (minor version is too high). + PhpVersionNumberCollection + .make(from: []).all + ) + + // 4. Precise members and constraint all around + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]) + .matching(constraint: "~7.0.1", strict: true), + // Only 7.0 with a patch version of .1 or higher is OK. + // In this example, 7.0.10 is OK but all other versions are too new. + PhpVersionNumberCollection + .make(from: ["7.0.10"]).all + ) + + // 5. Precise members but imprecise constraint (strict mode) + // In strict mode the constraint's patch version is assumed to be 0. + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]) + .matching(constraint: "~7.0", strict: true), + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]).all + ) + + // 6. Precise members but imprecise constraint (lenient mode) + // In lenient mode the constraint's patch version is assumed to be equal. + // (Strictness does not make any difference here, but both should be tested.) + XCTAssertEqual( + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]) + .matching(constraint: "~7.0", strict: false), + PhpVersionNumberCollection + .make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]).all + ) + } +} diff --git a/phpmon/Domain/Menu/MainMenu.swift b/phpmon/Domain/Menu/MainMenu.swift index 69f4c51..c9d9f1f 100644 --- a/phpmon/Domain/Menu/MainMenu.swift +++ b/phpmon/Domain/Menu/MainMenu.swift @@ -282,6 +282,10 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { } @objc func switchToPhpVersion(sender: PhpMenuItem) { + self.switchToPhpVersion(sender.version) + } + + @objc func switchToPhpVersion(_ version: String) { setBusyImage() PhpEnv.shared.isBusy = true @@ -305,8 +309,8 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { let sendLocalNotification = { LocalNotification.send( - title: String(format: "notification.version_changed_title".localized, sender.version), - subtitle: String(format: "notification.version_changed_desc".localized, sender.version) + title: String(format: "notification.version_changed_title".localized, version), + subtitle: String(format: "notification.version_changed_desc".localized, version) ) PhpEnv.phpInstall.notifyAboutBrokenPhpFpm() } @@ -321,7 +325,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate { } PhpEnv.switcher.performSwitch( - to: sender.version, + to: version, completion: completion ) } diff --git a/phpmon/Domain/Menu/StatusMenu.swift b/phpmon/Domain/Menu/StatusMenu.swift index 2644681..0a34b91 100644 --- a/phpmon/Domain/Menu/StatusMenu.swift +++ b/phpmon/Domain/Menu/StatusMenu.swift @@ -137,7 +137,7 @@ class StatusMenu : NSMenu { let longVersion = PhpEnv.shared.cachedPhpInstallations[shortVersion]!.longVersion let long = Preferences.preferences[.fullPhpVersionDynamicIcon] as! Bool - let versionString = long ? longVersion : shortVersion + let versionString = long ? longVersion.homebrewVersion : shortVersion let action = #selector(MainMenu.switchToPhpVersion(sender:)) let brew = (shortVersion == PhpEnv.brewPhpVersion) ? "php" : "php@\(shortVersion)" diff --git a/phpmon/Domain/SiteList/SiteListCell.swift b/phpmon/Domain/SiteList/SiteListCell.swift index 9f026c1..2c68f95 100644 --- a/phpmon/Domain/SiteList/SiteListCell.swift +++ b/phpmon/Domain/SiteList/SiteListCell.swift @@ -80,12 +80,13 @@ class SiteListCell: NSTableCellView var mapIndex: Int = NSApplication.ModalResponse.alertSecondButtonReturn.rawValue var map: [Int: String] = [:] - var versions: [String] = [] - // TODO: Based on the version constraint, insert the desired version to switch to - - versions.forEach { version in - alert.addButton(withTitle: "Switch to PHP \(version)") - map[mapIndex] = version + // Determine which installed versions would be ideal to switch to, + // but make sure to exclude the currently linked version + PhpEnv.shared.validVersions(for: site.composerPhp).filter({ version in + version.homebrewVersion != PhpEnv.phpInstall.version.short + }).forEach { version in + alert.addButton(withTitle: "Switch to PHP \(version.homebrewVersion)") + map[mapIndex] = version.homebrewVersion mapIndex += 1 } @@ -94,6 +95,7 @@ class SiteListCell: NSTableCellView if map.keys.contains(response.rawValue) { let version = map[response.rawValue]! print("Pressed button to switch to \(version)") + MainMenu.shared.switchToPhpVersion(version) } } } diff --git a/phpmon/Localizable.strings b/phpmon/Localizable.strings index 7d31ab9..7246903 100644 --- a/phpmon/Localizable.strings +++ b/phpmon/Localizable.strings @@ -156,7 +156,7 @@ problem manually, using your own Terminal app (this just shows you the output)." // Composer Version "alert.composer_php_requirement.title" = "`%@` has the following PHP requirement: \"php\": \"%@\"."; -"alert.composer_php_requirement.info" = "This required PHP version was determined by checking the %@ in `composer.json`.\n\nPlease note that the lockfile is not checked and this reflects the current Composer configuration file as it existed at the time of refreshing the site list."; +"alert.composer_php_requirement.info" = "This required PHP version was determined by checking the %@ in `composer.json` when the list was last refreshed."; // Force Reload Started "alert.force_reload.title" = "PHP Monitor will force reload the latest version of PHP";