mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-08 04:20:07 +02:00
✨ Add support for wildcard constraints (#224)
This commit is contained in:
@ -35,6 +35,7 @@ public struct PhpVersionNumberCollection: Equatable {
|
|||||||
- Parameter strict: Whether the patch version check is strict. See more below.
|
- Parameter strict: Whether the patch 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.
|
The strict mode does not matter if a patch version is provided for all versions in the collection.
|
||||||
|
It also does not matter for certain comparisons (e.g. when dealing with wildcards).
|
||||||
|
|
||||||
Strict mode assumes that any PHP version lacking precise patch information, e.g. inferred
|
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,
|
from Homebrew corresponds to the .0 patch version of that version. The default, which is imprecise,
|
||||||
@ -45,6 +46,7 @@ public struct PhpVersionNumberCollection: Equatable {
|
|||||||
|
|
||||||
Given versions 8.0.? and 8.1.?, but the requirement is ^8.0.1, in strict mode only 8.1.? will
|
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).
|
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 (with patch precision), use
|
When checking against actual PHP versions installed by the user (with patch precision), use
|
||||||
strict mode.
|
strict mode.
|
||||||
|
|
||||||
@ -52,11 +54,26 @@ public struct PhpVersionNumberCollection: Equatable {
|
|||||||
|
|
||||||
Given versions 8.0.? and 8.1.?, but the requirement is ^8.0.1, in non-strict mode version 8.0
|
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.
|
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).
|
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
|
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.)
|
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) -> [VersionNumber] {
|
public func matching(constraint: String, strict: Bool = false) -> [VersionNumber] {
|
||||||
|
if constraint == "*" {
|
||||||
|
return self.versions
|
||||||
|
}
|
||||||
|
|
||||||
|
if let version = VersionNumber.make(from: constraint, type: .wildCardPatch) {
|
||||||
|
// Wildcard for patch (e.g. "7.4.*") must match major and minor (any patch)
|
||||||
|
return self.versions.filter { $0.hasSameMajorAndMinor(version) }
|
||||||
|
}
|
||||||
|
|
||||||
|
if let version = VersionNumber.make(from: constraint, type: .wildCardMinor) {
|
||||||
|
// Strict constraint (e.g. "7.*") -> must only match major (any patch, minor)
|
||||||
|
return self.versions.filter { $0.isSameMajorVersionAs(version) }
|
||||||
|
}
|
||||||
|
|
||||||
if let version = VersionNumber.make(from: constraint, type: .versionOnly) {
|
if let version = VersionNumber.make(from: constraint, type: .versionOnly) {
|
||||||
// Strict constraint (e.g. "7.0") -> returns specific version
|
// Strict constraint (e.g. "7.0") -> returns specific version
|
||||||
return self.versions.filter { $0.isSameAs(version, strict) }
|
return self.versions.filter { $0.isSameAs(version, strict) }
|
||||||
|
@ -39,6 +39,8 @@ public struct VersionNumber: Equatable, Hashable {
|
|||||||
|
|
||||||
public enum MatchType: String {
|
public enum MatchType: String {
|
||||||
case versionOnly = #"^(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
case versionOnly = #"^(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
||||||
|
case wildCardPatch = #"^(?<major>\d+).(?<minor>\d+).?(?<patch>\*)?\z"#
|
||||||
|
case wildCardMinor = #"^(?<major>\d+).(?<minor>\*)?\z"#
|
||||||
case caretVersionRange = #"^\^(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
case caretVersionRange = #"^\^(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
||||||
case tildeVersionRange = #"^~(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
case tildeVersionRange = #"^~(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
||||||
case greaterThanOrEqual = #"^>=(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
case greaterThanOrEqual = #"^>=(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
||||||
@ -64,21 +66,25 @@ public struct VersionNumber: Equatable, Hashable {
|
|||||||
range: NSRange(location: 0, length: versionString.count)
|
range: NSRange(location: 0, length: versionString.count)
|
||||||
).first
|
).first
|
||||||
|
|
||||||
if match != nil {
|
guard let match else { return nil }
|
||||||
let major = Int(
|
|
||||||
versionString[Range(match!.range(withName: "major"), in: versionString)!]
|
let major = Int(versionString[Range(match.range(withName: "major"), in: versionString)!])!
|
||||||
)!
|
var minor: Int = 0
|
||||||
let minor = Int(
|
var patch: Int?
|
||||||
versionString[Range(match!.range(withName: "minor"), in: versionString)!]
|
|
||||||
)!
|
if let minorRange = Range(match.range(withName: "minor"), in: versionString) {
|
||||||
var patch: Int?
|
let value = versionString[minorRange] as String
|
||||||
if let minorRange = Range(match!.range(withName: "patch"), in: versionString) {
|
// Zero is the fallback if a wildcard was used
|
||||||
patch = Int(versionString[minorRange])
|
minor = Int(value) ?? 0
|
||||||
}
|
|
||||||
return Self(major: major, minor: minor, patch: patch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
if let patchRange = Range(match.range(withName: "patch"), in: versionString) {
|
||||||
|
let value = versionString[patchRange] as String
|
||||||
|
// nil is the fallback if a wildcard was used
|
||||||
|
patch = Int(value) ?? nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return Self(major: major, minor: minor, patch: patch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Comparison Logic
|
// MARK: Comparison Logic
|
||||||
@ -93,6 +99,10 @@ public struct VersionNumber: Equatable, Hashable {
|
|||||||
&& (strict ? self.patch(strict, version) == version.patch(strict) : true)
|
&& (strict ? self.patch(strict, version) == version.patch(strict) : true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal func hasSameMajorAndMinor(_ version: VersionNumber) -> Bool {
|
||||||
|
return self.major == version.major && self.minor == version.minor
|
||||||
|
}
|
||||||
|
|
||||||
internal func isNewerThan(_ version: VersionNumber, _ strict: Bool) -> Bool {
|
internal func isNewerThan(_ version: VersionNumber, _ strict: Bool) -> Bool {
|
||||||
return (
|
return (
|
||||||
self.major > version.major ||
|
self.major > version.major ||
|
||||||
|
@ -22,7 +22,6 @@ class InternalSwitcher: PhpSwitcher {
|
|||||||
*/
|
*/
|
||||||
func performSwitch(to version: String) async {
|
func performSwitch(to version: String) async {
|
||||||
Log.info("Switching to \(version), unlinking all versions...")
|
Log.info("Switching to \(version), unlinking all versions...")
|
||||||
|
|
||||||
let versions = getVersionsToBeHandled(version)
|
let versions = getVersionsToBeHandled(version)
|
||||||
|
|
||||||
await withTaskGroup(of: String.self, body: { group in
|
await withTaskGroup(of: String.self, body: { group in
|
||||||
|
@ -44,6 +44,53 @@ class PhpVersionNumberTest: XCTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func test_can_parse_wildcard() throws {
|
||||||
|
let version = VersionNumber.make(from: "7.*", type: .wildCardMinor)
|
||||||
|
XCTAssertNotNil(version)
|
||||||
|
XCTAssertEqual(version!.major, 7)
|
||||||
|
XCTAssertEqual(version!.minor, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func test_can_check_wildcard_version_constraint() throws {
|
||||||
|
// Wildcard for patch only
|
||||||
|
XCTAssertEqual(
|
||||||
|
PhpVersionNumberCollection
|
||||||
|
.make(from: ["7.4.10", "7.3.10", "7.3.9"])
|
||||||
|
.matching(constraint: "7.3.*", strict: false),
|
||||||
|
PhpVersionNumberCollection
|
||||||
|
.make(from: ["7.3.10", "7.3.9"]).all
|
||||||
|
)
|
||||||
|
|
||||||
|
// Wildcard for minor
|
||||||
|
XCTAssertEqual(
|
||||||
|
PhpVersionNumberCollection
|
||||||
|
.make(from: ["8.0.0", "7.4.10", "7.3.10", "7.3.9"])
|
||||||
|
.matching(constraint: "7.*", strict: false),
|
||||||
|
PhpVersionNumberCollection
|
||||||
|
.make(from: ["7.4.10", "7.3.10", "7.3.9"]).all
|
||||||
|
)
|
||||||
|
|
||||||
|
// Full wildcard
|
||||||
|
XCTAssertEqual(
|
||||||
|
PhpVersionNumberCollection
|
||||||
|
.make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"])
|
||||||
|
.matching(constraint: "*", strict: false),
|
||||||
|
PhpVersionNumberCollection
|
||||||
|
.make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]).all
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_can_check_any_version_constraint() throws {
|
||||||
|
XCTAssertEqual(
|
||||||
|
PhpVersionNumberCollection
|
||||||
|
.make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"])
|
||||||
|
.matching(constraint: "*", strict: false),
|
||||||
|
PhpVersionNumberCollection
|
||||||
|
.make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]).all
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func test_can_check_fixed_constraints() throws {
|
func test_can_check_fixed_constraints() throws {
|
||||||
XCTAssertEqual(
|
XCTAssertEqual(
|
||||||
PhpVersionNumberCollection
|
PhpVersionNumberCollection
|
||||||
|
Reference in New Issue
Block a user