diff --git a/Sources/apk/Index/ApkIndex.swift b/Sources/apk/Index/ApkIndex.swift index b62dd34..845b87c 100644 --- a/Sources/apk/Index/ApkIndex.swift +++ b/Sources/apk/Index/ApkIndex.swift @@ -1,5 +1,5 @@ /* - * darwin-apk © 2024 Gay Pizza Specifications + * darwin-apk © 2024, 2025 Gay Pizza Specifications * SPDX-License-Identifier: Apache-2.0 */ @@ -25,21 +25,15 @@ public extension ApkIndex { func resolve(requirement: ApkVersionRequirement) -> ApkIndexPackage? { self.packages.first { pkg in - guard pkg.name == requirement.name || - pkg.provides.contains(where: { $0.name == requirement.name }) else { - return false - } - return requirement.versionSpec.satisfied(by: pkg.version) + return (pkg.name == requirement.name && requirement.versionSpec.satisfied(by: pkg.version)) + || pkg.provides.contains(where: { $0.satisfies(requirement) }) } } func resolveIndex(requirement: ApkVersionRequirement) -> Index? { self.packages.firstIndex { pkg in - guard pkg.name == requirement.name || - pkg.provides.contains(where: { $0.name == requirement.name }) else { - return false - } - return requirement.versionSpec.satisfied(by: pkg.version) + return (pkg.name == requirement.name && requirement.versionSpec.satisfied(by: pkg.version)) + || pkg.provides.contains(where: { $0.satisfies(requirement) }) } } } diff --git a/Sources/apk/Index/ApkIndexPackage.swift b/Sources/apk/Index/ApkIndexPackage.swift index 0e28277..2b160aa 100644 --- a/Sources/apk/Index/ApkIndexPackage.swift +++ b/Sources/apk/Index/ApkIndexPackage.swift @@ -93,7 +93,7 @@ extension ApkIndexPackage { case "p": do { provides = try record.value.split(separator: " ") - .map { .init(requirement: try .init(extract: $0)) } + .map { try .init(requirement: try .init(extract: $0)) } } catch { throw .badValue(key: record.key, cause: error.localizedDescription) } case "i": do { @@ -207,7 +207,7 @@ extension ApkIndexPackage: CustomStringConvertible { s += "dependencies: - \(self.dependencies.map(\.requirement.description).joined(separator: " "))\n" } if !self.provides.isEmpty { - s += "provides: ----- \(self.provides.map(\.name).joined(separator: " "))\n" + s += "provides: ----- \(self.provides.map(\.description).joined(separator: " "))\n" } if !self.installIf.isEmpty { s += "install if: --- \(self.installIf.map(\.requirement.description).joined(separator: " "))\n" diff --git a/Sources/apk/Index/ApkIndexProvides.swift b/Sources/apk/Index/ApkIndexProvides.swift index cfc0a3d..381a118 100644 --- a/Sources/apk/Index/ApkIndexProvides.swift +++ b/Sources/apk/Index/ApkIndexProvides.swift @@ -1,12 +1,60 @@ /* - * darwin-apk © 2024 Gay Pizza Specifications + * darwin-apk © 2024, 2025 Gay Pizza Specifications * SPDX-License-Identifier: Apache-2.0 */ -public struct ApkIndexProvides: Hashable, Sendable { - let name: String +import Foundation - init(requirement: ApkVersionRequirement) { - self.name = requirement.name +public enum ApkIndexProvides: Hashable, Sendable { + case any(name: String) + case specific(name: String, version: String) +} + +extension ApkIndexProvides { + init(requirement: ApkVersionRequirement) throws(ProvidesError) { + self = switch requirement.versionSpec { + case .any(invert: false): + .any(name: requirement.name) + case .constraint(invert: false, op: .equals, let version): + .specific(name: requirement.name, version: version) + default: + throw .badConstraint + } + } + + func satisfies(_ requirement: ApkVersionRequirement) -> Bool { + switch self { + case .any(let name): + return requirement.name == name + case .specific(let name, let version): + return requirement.name == name && + requirement.versionSpec.satisfied(by: version) + } + } + + enum ProvidesError: Error, LocalizedError { + case badConstraint + + var errorDescription: String? { + switch self { + case .badConstraint: "Invalid constraint type, must only be equals" + } + } + } +} + +extension ApkIndexProvides: CustomStringConvertible { + public var description: String { + switch self { + case .any(let name): name + case .specific(let name, let version): "\(name)=\(version)" + } + } + + public var name: String { + switch self { + case .any(let name): name + case .specific(let name, _): name + } } }