From 33754cc014f1241222be0c2f83d797a0f4609905 Mon Sep 17 00:00:00 2001 From: Tamar Milchtaich Lavi Date: Mon, 17 Mar 2025 14:50:02 +0200 Subject: [PATCH 1/3] feat(PBXFileReference): support XCFramework expectedSignature property Support XCFrameworks expectedSignature property, and add the expected expectedSignature to the target dependency, to be verified against the actual signature. --- .../DependenciesGraph/DependenciesGraph.swift | 7 ++++- .../XcodeGraph/Graph/GraphDependency.swift | 5 +++- .../Models/Metadata/XCFrameworkMetadata.swift | 11 +++++--- .../XcodeGraph/Models/TargetDependency.swift | 26 ++++++++++++++++--- .../TargetDependency+Extensions.swift | 2 +- .../PBXFrameworksBuildPhaseMapper.swift | 2 +- .../Targets/PBXTargetDependencyMapper.swift | 15 ++++++----- .../TargetDependency+GraphMapping.swift | 11 +++++--- .../Utilities/PathDependencyMapper.swift | 7 ++--- .../XCFrameworkMetadataProvider.swift | 8 +++--- 10 files changed, 68 insertions(+), 26 deletions(-) diff --git a/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift b/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift index 639bd16b..6f8491ed 100644 --- a/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift +++ b/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift @@ -33,9 +33,14 @@ public struct DependenciesGraph: Equatable, Codable, Sendable { name: String = "Test", // swiftlint:disable:next force_try path: AbsolutePath = AbsolutePath.root.appending(try! RelativePath(validating: "Test.xcframework")), + expectedSignature: XCFrameworkSignature = .unsigned, status: LinkingStatus = .required ) -> DependenciesGraph { - let externalDependencies = [name: [TargetDependency.xcframework(path: path, status: status)]] + let externalDependencies = [name: [TargetDependency.xcframework( + path: path, + expectedSignature: expectedSignature, + status: status + )]] return .init( externalDependencies: externalDependencies, diff --git a/Sources/XcodeGraph/Graph/GraphDependency.swift b/Sources/XcodeGraph/Graph/GraphDependency.swift index 37988426..35c514d9 100644 --- a/Sources/XcodeGraph/Graph/GraphDependency.swift +++ b/Sources/XcodeGraph/Graph/GraphDependency.swift @@ -10,6 +10,7 @@ public enum GraphDependency: Hashable, CustomStringConvertible, Comparable, Coda public let status: LinkingStatus public let swiftModules: [AbsolutePath] public let moduleMaps: [AbsolutePath] + public let expectedSignature: String? public init( path: AbsolutePath, @@ -19,7 +20,8 @@ public enum GraphDependency: Hashable, CustomStringConvertible, Comparable, Coda status: LinkingStatus, macroPath _: AbsolutePath?, swiftModules: [AbsolutePath], - moduleMaps: [AbsolutePath] + moduleMaps: [AbsolutePath], + expectedSignature: String? = nil ) { self.path = path self.infoPlist = infoPlist @@ -28,6 +30,7 @@ public enum GraphDependency: Hashable, CustomStringConvertible, Comparable, Coda self.status = status self.swiftModules = swiftModules self.moduleMaps = moduleMaps + self.expectedSignature = expectedSignature } public var description: String { diff --git a/Sources/XcodeGraph/Models/Metadata/XCFrameworkMetadata.swift b/Sources/XcodeGraph/Models/Metadata/XCFrameworkMetadata.swift index 72e24715..c0318077 100644 --- a/Sources/XcodeGraph/Models/Metadata/XCFrameworkMetadata.swift +++ b/Sources/XcodeGraph/Models/Metadata/XCFrameworkMetadata.swift @@ -13,6 +13,7 @@ public struct XCFrameworkMetadata: Equatable { public var swiftModules: [AbsolutePath] /// All `.modulemap` files present in the `.xcframework` public var moduleMaps: [AbsolutePath] + public var expectedSignature: XCFrameworkSignature? public init( path: AbsolutePath, @@ -22,7 +23,8 @@ public struct XCFrameworkMetadata: Equatable { status: LinkingStatus, macroPath: AbsolutePath?, swiftModules: [AbsolutePath] = [], - moduleMaps: [AbsolutePath] = [] + moduleMaps: [AbsolutePath] = [], + expectedSignature: XCFrameworkSignature? = nil ) { self.path = path self.infoPlist = infoPlist @@ -32,6 +34,7 @@ public struct XCFrameworkMetadata: Equatable { self.macroPath = macroPath self.swiftModules = swiftModules self.moduleMaps = moduleMaps + self.expectedSignature = expectedSignature } } @@ -46,7 +49,8 @@ public struct XCFrameworkMetadata: Equatable { status: LinkingStatus = .required, macroPath: AbsolutePath? = nil, swiftModules: [AbsolutePath] = [], - moduleMaps: [AbsolutePath] = [] + moduleMaps: [AbsolutePath] = [], + expectedSignature: XCFrameworkSignature? = nil ) -> XCFrameworkMetadata { XCFrameworkMetadata( path: path, @@ -56,7 +60,8 @@ public struct XCFrameworkMetadata: Equatable { status: status, macroPath: macroPath, swiftModules: swiftModules, - moduleMaps: moduleMaps + moduleMaps: moduleMaps, + expectedSignature: expectedSignature ) } } diff --git a/Sources/XcodeGraph/Models/TargetDependency.swift b/Sources/XcodeGraph/Models/TargetDependency.swift index 1c60d0bb..a778b33e 100644 --- a/Sources/XcodeGraph/Models/TargetDependency.swift +++ b/Sources/XcodeGraph/Models/TargetDependency.swift @@ -7,6 +7,24 @@ public enum LinkingStatus: String, Hashable, Codable, Sendable { case none } +public enum XCFrameworkSignature: Equatable, Hashable, Codable, Sendable { + case unsigned + case signedWithAppleCertificate(teamIdentifier: String, teamName: String) + case selfSigned(fingerprint: String) + + public func signatureString() -> String? { + switch self { + case .unsigned: + return nil + case let .selfSigned(fingerprint: fingerprint): + return "SelfSigned:\(fingerprint)" + case let .signedWithAppleCertificate(teamIdentifier: teamIdentifier, teamName: teamName): + return "AppleDeveloperProgram:\(teamIdentifier):\(teamName)" + } + } +} + + public enum TargetDependency: Equatable, Hashable, Codable, Sendable { public enum PackageType: String, Equatable, Hashable, Codable, Sendable { case runtime @@ -18,7 +36,7 @@ public enum TargetDependency: Equatable, Hashable, Codable, Sendable { case target(name: String, status: LinkingStatus = .required, condition: PlatformCondition? = nil) case project(target: String, path: AbsolutePath, status: LinkingStatus = .required, condition: PlatformCondition? = nil) case framework(path: AbsolutePath, status: LinkingStatus, condition: PlatformCondition? = nil) - case xcframework(path: AbsolutePath, status: LinkingStatus, condition: PlatformCondition? = nil) + case xcframework(path: AbsolutePath, expectedSignature: XCFrameworkSignature?, status: LinkingStatus, condition: PlatformCondition? = nil) case library( path: AbsolutePath, publicHeaders: AbsolutePath, @@ -37,7 +55,7 @@ public enum TargetDependency: Equatable, Hashable, Codable, Sendable { condition case .framework(path: _, status: _, condition: let condition): condition - case .xcframework(path: _, status: _, condition: let condition): + case .xcframework(path: _, expectedSignature: _, status: _, condition: let condition): condition case .library(path: _, publicHeaders: _, swiftModuleMap: _, condition: let condition): condition @@ -57,8 +75,8 @@ public enum TargetDependency: Equatable, Hashable, Codable, Sendable { return .project(target: target, path: path, status: status, condition: condition) case .framework(path: let path, status: let status, condition: _): return .framework(path: path, status: status, condition: condition) - case .xcframework(path: let path, status: let status, condition: _): - return .xcframework(path: path, status: status, condition: condition) + case .xcframework(path: let path, expectedSignature: let expectedSignature, status: let status, condition: _): + return .xcframework(path: path, expectedSignature:expectedSignature, status: status, condition: condition) case .library(path: let path, publicHeaders: let headers, swiftModuleMap: let moduleMap, condition: _): return .library(path: path, publicHeaders: headers, swiftModuleMap: moduleMap, condition: condition) case .package(product: let product, type: let type, condition: _): diff --git a/Sources/XcodeGraphMapper/Extensions/TargetDependency+Extensions.swift b/Sources/XcodeGraphMapper/Extensions/TargetDependency+Extensions.swift index c92c1fce..6642bac8 100644 --- a/Sources/XcodeGraphMapper/Extensions/TargetDependency+Extensions.swift +++ b/Sources/XcodeGraphMapper/Extensions/TargetDependency+Extensions.swift @@ -14,7 +14,7 @@ extension TargetDependency { return product case let .framework(path, _, _): return path.basenameWithoutExt - case let .xcframework(path, _, _): + case let .xcframework(path, _, _, _): return path.basenameWithoutExt case let .library(path, _, _, _): return path.basenameWithoutExt diff --git a/Sources/XcodeGraphMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift b/Sources/XcodeGraphMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift index 0317421f..6b82d874 100644 --- a/Sources/XcodeGraphMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift +++ b/Sources/XcodeGraphMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift @@ -97,7 +97,7 @@ struct PBXFrameworksBuildPhaseMapper: PBXFrameworksBuildPhaseMapping { .throwing(PBXFrameworksBuildPhaseMappingError.missingFilePath(name: fileRef.name)) let absolutePath = try AbsolutePath(validating: filePathString) - return try pathMapper.map(path: absolutePath, condition: nil) + return try pathMapper.map(path: absolutePath, expectedSignature: nil, condition: nil) } } diff --git a/Sources/XcodeGraphMapper/Mappers/Targets/PBXTargetDependencyMapper.swift b/Sources/XcodeGraphMapper/Mappers/Targets/PBXTargetDependencyMapper.swift index f06e4eb1..91a4ec14 100644 --- a/Sources/XcodeGraphMapper/Mappers/Targets/PBXTargetDependencyMapper.swift +++ b/Sources/XcodeGraphMapper/Mappers/Targets/PBXTargetDependencyMapper.swift @@ -54,7 +54,7 @@ struct PBXTargetDependencyMapper: PBXTargetDependencyMapping { case .nativeTarget: return try mapNativeTargetProxy(targetProxy, condition: condition, xcodeProj: xcodeProj) case .reference: - return try mapReferenceProxy(targetProxy, condition: condition, xcodeProj: xcodeProj) + return try mapReferenceProxy(targetProxy, condition: condition, xcodeProj: xcodeProj) case .other, .none: throw TargetDependencyMappingError.unsupportedProxyType(dependency.name) } @@ -107,13 +107,15 @@ struct PBXTargetDependencyMapper: PBXTargetDependencyMapping { // File-based dependency if let fileRef = object as? PBXFileReference { return try mapFileDependency( - pathString: fileRef.path, - condition: condition, - xcodeProj: xcodeProj + pathString: fileRef.path, + expectedSignature: nil, + condition: condition, + xcodeProj: xcodeProj ) } else if let refProxy = object as? PBXReferenceProxy { return try mapFileDependency( pathString: refProxy.path, + expectedSignature: nil, condition: condition, xcodeProj: xcodeProj ) @@ -127,16 +129,17 @@ struct PBXTargetDependencyMapper: PBXTargetDependencyMapping { ) } } - /// Maps file-based dependencies (e.g., frameworks, libraries) into `TargetDependency` models. /// - Parameters: /// - pathString: The path string for the file-based dependency (relative or absolute). + /// - expectedSignature: The expected signature if `path` is of a signed XCFramework, `nil` otherwise. /// - condition: An optional platform condition. /// - xcodeProj: The Xcode project reference for resolving the directory structure. /// - Returns: A `TargetDependency` reflecting the file’s extension (framework, library, etc.). /// - Throws: If the path is missing or invalid. private func mapFileDependency( pathString: String?, + expectedSignature:XCFrameworkSignature?, condition: PlatformCondition?, xcodeProj: XcodeProj ) throws -> TargetDependency { @@ -144,7 +147,7 @@ struct PBXTargetDependencyMapper: PBXTargetDependencyMapping { TargetDependencyMappingError.missingFileReference("Path string is nil in file dependency.") ) let path = xcodeProj.srcPath.appending(try RelativePath(validating: pathString)) - return try pathMapper.map(path: path, condition: condition) + return try pathMapper.map(path: path, expectedSignature:expectedSignature, condition: condition) } } diff --git a/Sources/XcodeGraphMapper/Mappers/Targets/TargetDependency+GraphMapping.swift b/Sources/XcodeGraphMapper/Mappers/Targets/TargetDependency+GraphMapping.swift index 46434e64..00d7e423 100644 --- a/Sources/XcodeGraphMapper/Mappers/Targets/TargetDependency+GraphMapping.swift +++ b/Sources/XcodeGraphMapper/Mappers/Targets/TargetDependency+GraphMapping.swift @@ -51,8 +51,12 @@ extension TargetDependency { status: status ) - case let .xcframework(path, status, _): - let metadata = try await xcframeworkMetadataProvider.loadMetadata(at: path, status: status) + case let .xcframework(path, expectedSignature, status, _): + let metadata = try await xcframeworkMetadataProvider.loadMetadata( + at: path, + expectedSignature: expectedSignature, + status: status + ) return .xcframework( .init( path: path, @@ -62,7 +66,8 @@ extension TargetDependency { status: status, macroPath: metadata.macroPath, swiftModules: metadata.swiftModules, - moduleMaps: metadata.moduleMaps + moduleMaps: metadata.moduleMaps, + expectedSignature: metadata.expectedSignature?.signatureString() ) ) diff --git a/Sources/XcodeGraphMapper/Utilities/PathDependencyMapper.swift b/Sources/XcodeGraphMapper/Utilities/PathDependencyMapper.swift index 417c1f6d..0fb92cc9 100644 --- a/Sources/XcodeGraphMapper/Utilities/PathDependencyMapper.swift +++ b/Sources/XcodeGraphMapper/Utilities/PathDependencyMapper.swift @@ -8,22 +8,23 @@ protocol PathDependencyMapping { /// /// - Parameters: /// - path: The file path to map. + /// - expectedSignature: The expected signature if `path` is of a signed XCFramework, `nil` otherwise. /// - condition: An optional platform condition (e.g., iOS only). /// - Returns: The corresponding `TargetDependency`, if the path extension is recognized. /// - Throws: `PathDependencyError.invalidExtension` if the file extension is not supported. - func map(path: AbsolutePath, condition: PlatformCondition?) throws -> TargetDependency + func map(path: AbsolutePath, expectedSignature:XCFrameworkSignature?, condition: PlatformCondition?) throws -> TargetDependency } /// A mapper that converts file paths (like `.framework`, `.xcframework`, or libraries) to `TargetDependency` models. struct PathDependencyMapper: PathDependencyMapping { - func map(path: AbsolutePath, condition: PlatformCondition?) throws -> TargetDependency { + func map(path: AbsolutePath, expectedSignature: XCFrameworkSignature? = nil, condition: PlatformCondition?) throws -> TargetDependency { let status: LinkingStatus = .required switch path.fileExtension { case .framework: return .framework(path: path, status: status, condition: condition) case .xcframework: - return .xcframework(path: path, status: status, condition: condition) + return .xcframework(path: path, expectedSignature: expectedSignature ?? .unsigned, status: status, condition: condition) case .dynamicLibrary, .textBasedDynamicLibrary, .staticLibrary: return .library( path: path, diff --git a/Sources/XcodeMetadata/Providers/XCFrameworkMetadataProvider.swift b/Sources/XcodeMetadata/Providers/XCFrameworkMetadataProvider.swift index 8cc8149e..e8e2121f 100644 --- a/Sources/XcodeMetadata/Providers/XCFrameworkMetadataProvider.swift +++ b/Sources/XcodeMetadata/Providers/XCFrameworkMetadataProvider.swift @@ -49,9 +49,9 @@ public protocol XCFrameworkMetadataProviding: PrecompiledMetadataProviding { /// - Parameter binaryPath: Path to the binary. func uuids(binaryPath: AbsolutePath) throws -> Set - /// Loads all the metadata associated with an XCFramework at the specified path + /// Loads all the metadata associated with an XCFramework at the specified path, and expected signature if signed /// - Note: This performs various shell calls and disk operations - func loadMetadata(at path: AbsolutePath, status: LinkingStatus) async throws + func loadMetadata(at path: AbsolutePath, expectedSignature: XCFrameworkSignature?, status: LinkingStatus) async throws -> XCFrameworkMetadata /// Returns the info.plist of the xcframework at the given path. @@ -75,6 +75,7 @@ public final class XCFrameworkMetadataProvider: PrecompiledMetadataProvider, public func loadMetadata( at path: AbsolutePath, + expectedSignature: XCFrameworkSignature?, status: LinkingStatus ) async throws -> XCFrameworkMetadata { guard try await fileSystem.exists(path) else { @@ -93,7 +94,8 @@ public final class XCFrameworkMetadataProvider: PrecompiledMetadataProvider, status: status, macroPath: try await macroPath(xcframeworkPath: path), swiftModules: try await fileSystem.glob(directory: path, include: ["**/*.swiftmodule"]).collect().sorted(), - moduleMaps: try await fileSystem.glob(directory: path, include: ["**/*.modulemap"]).collect().sorted() + moduleMaps: try await fileSystem.glob(directory: path, include: ["**/*.modulemap"]).collect().sorted(), + expectedSignature: expectedSignature ) } From b93a0c1f9794ad785826618f7d8fde9ca0112120 Mon Sep 17 00:00:00 2001 From: Pedro Date: Wed, 30 Apr 2025 10:35:04 +0200 Subject: [PATCH 2/3] Fix linting issues --- .../DependenciesGraph/DependenciesGraph.swift | 10 +++++----- Sources/XcodeGraph/Models/TargetDependency.swift | 10 +++++++--- .../Phases/PBXFrameworksBuildPhaseMapper.swift | 2 +- .../Targets/PBXTargetDependencyMapper.swift | 15 ++++++++------- .../Targets/TargetDependency+GraphMapping.swift | 10 +++++----- .../Utilities/PathDependencyMapper.swift | 16 +++++++++++++--- .../Providers/XCFrameworkMetadataProvider.swift | 2 +- 7 files changed, 40 insertions(+), 25 deletions(-) diff --git a/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift b/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift index 6f8491ed..b90e332a 100644 --- a/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift +++ b/Sources/XcodeGraph/DependenciesGraph/DependenciesGraph.swift @@ -36,11 +36,11 @@ public struct DependenciesGraph: Equatable, Codable, Sendable { expectedSignature: XCFrameworkSignature = .unsigned, status: LinkingStatus = .required ) -> DependenciesGraph { - let externalDependencies = [name: [TargetDependency.xcframework( - path: path, - expectedSignature: expectedSignature, - status: status - )]] + let externalDependencies = [name: [TargetDependency.xcframework( + path: path, + expectedSignature: expectedSignature, + status: status + )]] return .init( externalDependencies: externalDependencies, diff --git a/Sources/XcodeGraph/Models/TargetDependency.swift b/Sources/XcodeGraph/Models/TargetDependency.swift index a778b33e..54ddb418 100644 --- a/Sources/XcodeGraph/Models/TargetDependency.swift +++ b/Sources/XcodeGraph/Models/TargetDependency.swift @@ -24,7 +24,6 @@ public enum XCFrameworkSignature: Equatable, Hashable, Codable, Sendable { } } - public enum TargetDependency: Equatable, Hashable, Codable, Sendable { public enum PackageType: String, Equatable, Hashable, Codable, Sendable { case runtime @@ -36,7 +35,12 @@ public enum TargetDependency: Equatable, Hashable, Codable, Sendable { case target(name: String, status: LinkingStatus = .required, condition: PlatformCondition? = nil) case project(target: String, path: AbsolutePath, status: LinkingStatus = .required, condition: PlatformCondition? = nil) case framework(path: AbsolutePath, status: LinkingStatus, condition: PlatformCondition? = nil) - case xcframework(path: AbsolutePath, expectedSignature: XCFrameworkSignature?, status: LinkingStatus, condition: PlatformCondition? = nil) + case xcframework( + path: AbsolutePath, + expectedSignature: XCFrameworkSignature?, + status: LinkingStatus, + condition: PlatformCondition? = nil + ) case library( path: AbsolutePath, publicHeaders: AbsolutePath, @@ -76,7 +80,7 @@ public enum TargetDependency: Equatable, Hashable, Codable, Sendable { case .framework(path: let path, status: let status, condition: _): return .framework(path: path, status: status, condition: condition) case .xcframework(path: let path, expectedSignature: let expectedSignature, status: let status, condition: _): - return .xcframework(path: path, expectedSignature:expectedSignature, status: status, condition: condition) + return .xcframework(path: path, expectedSignature: expectedSignature, status: status, condition: condition) case .library(path: let path, publicHeaders: let headers, swiftModuleMap: let moduleMap, condition: _): return .library(path: path, publicHeaders: headers, swiftModuleMap: moduleMap, condition: condition) case .package(product: let product, type: let type, condition: _): diff --git a/Sources/XcodeGraphMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift b/Sources/XcodeGraphMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift index 6b82d874..27d1211f 100644 --- a/Sources/XcodeGraphMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift +++ b/Sources/XcodeGraphMapper/Mappers/Phases/PBXFrameworksBuildPhaseMapper.swift @@ -97,7 +97,7 @@ struct PBXFrameworksBuildPhaseMapper: PBXFrameworksBuildPhaseMapping { .throwing(PBXFrameworksBuildPhaseMappingError.missingFilePath(name: fileRef.name)) let absolutePath = try AbsolutePath(validating: filePathString) - return try pathMapper.map(path: absolutePath, expectedSignature: nil, condition: nil) + return try pathMapper.map(path: absolutePath, expectedSignature: nil, condition: nil) } } diff --git a/Sources/XcodeGraphMapper/Mappers/Targets/PBXTargetDependencyMapper.swift b/Sources/XcodeGraphMapper/Mappers/Targets/PBXTargetDependencyMapper.swift index 91a4ec14..dc90edb5 100644 --- a/Sources/XcodeGraphMapper/Mappers/Targets/PBXTargetDependencyMapper.swift +++ b/Sources/XcodeGraphMapper/Mappers/Targets/PBXTargetDependencyMapper.swift @@ -54,7 +54,7 @@ struct PBXTargetDependencyMapper: PBXTargetDependencyMapping { case .nativeTarget: return try mapNativeTargetProxy(targetProxy, condition: condition, xcodeProj: xcodeProj) case .reference: - return try mapReferenceProxy(targetProxy, condition: condition, xcodeProj: xcodeProj) + return try mapReferenceProxy(targetProxy, condition: condition, xcodeProj: xcodeProj) case .other, .none: throw TargetDependencyMappingError.unsupportedProxyType(dependency.name) } @@ -107,10 +107,10 @@ struct PBXTargetDependencyMapper: PBXTargetDependencyMapping { // File-based dependency if let fileRef = object as? PBXFileReference { return try mapFileDependency( - pathString: fileRef.path, - expectedSignature: nil, - condition: condition, - xcodeProj: xcodeProj + pathString: fileRef.path, + expectedSignature: nil, + condition: condition, + xcodeProj: xcodeProj ) } else if let refProxy = object as? PBXReferenceProxy { return try mapFileDependency( @@ -129,6 +129,7 @@ struct PBXTargetDependencyMapper: PBXTargetDependencyMapping { ) } } + /// Maps file-based dependencies (e.g., frameworks, libraries) into `TargetDependency` models. /// - Parameters: /// - pathString: The path string for the file-based dependency (relative or absolute). @@ -139,7 +140,7 @@ struct PBXTargetDependencyMapper: PBXTargetDependencyMapping { /// - Throws: If the path is missing or invalid. private func mapFileDependency( pathString: String?, - expectedSignature:XCFrameworkSignature?, + expectedSignature: XCFrameworkSignature?, condition: PlatformCondition?, xcodeProj: XcodeProj ) throws -> TargetDependency { @@ -147,7 +148,7 @@ struct PBXTargetDependencyMapper: PBXTargetDependencyMapping { TargetDependencyMappingError.missingFileReference("Path string is nil in file dependency.") ) let path = xcodeProj.srcPath.appending(try RelativePath(validating: pathString)) - return try pathMapper.map(path: path, expectedSignature:expectedSignature, condition: condition) + return try pathMapper.map(path: path, expectedSignature: expectedSignature, condition: condition) } } diff --git a/Sources/XcodeGraphMapper/Mappers/Targets/TargetDependency+GraphMapping.swift b/Sources/XcodeGraphMapper/Mappers/Targets/TargetDependency+GraphMapping.swift index 00d7e423..adede7ef 100644 --- a/Sources/XcodeGraphMapper/Mappers/Targets/TargetDependency+GraphMapping.swift +++ b/Sources/XcodeGraphMapper/Mappers/Targets/TargetDependency+GraphMapping.swift @@ -52,11 +52,11 @@ extension TargetDependency { ) case let .xcframework(path, expectedSignature, status, _): - let metadata = try await xcframeworkMetadataProvider.loadMetadata( - at: path, - expectedSignature: expectedSignature, - status: status - ) + let metadata = try await xcframeworkMetadataProvider.loadMetadata( + at: path, + expectedSignature: expectedSignature, + status: status + ) return .xcframework( .init( path: path, diff --git a/Sources/XcodeGraphMapper/Utilities/PathDependencyMapper.swift b/Sources/XcodeGraphMapper/Utilities/PathDependencyMapper.swift index 0fb92cc9..b8e9f758 100644 --- a/Sources/XcodeGraphMapper/Utilities/PathDependencyMapper.swift +++ b/Sources/XcodeGraphMapper/Utilities/PathDependencyMapper.swift @@ -12,19 +12,29 @@ protocol PathDependencyMapping { /// - condition: An optional platform condition (e.g., iOS only). /// - Returns: The corresponding `TargetDependency`, if the path extension is recognized. /// - Throws: `PathDependencyError.invalidExtension` if the file extension is not supported. - func map(path: AbsolutePath, expectedSignature:XCFrameworkSignature?, condition: PlatformCondition?) throws -> TargetDependency + func map(path: AbsolutePath, expectedSignature: XCFrameworkSignature?, condition: PlatformCondition?) throws + -> TargetDependency } /// A mapper that converts file paths (like `.framework`, `.xcframework`, or libraries) to `TargetDependency` models. struct PathDependencyMapper: PathDependencyMapping { - func map(path: AbsolutePath, expectedSignature: XCFrameworkSignature? = nil, condition: PlatformCondition?) throws -> TargetDependency { + func map( + path: AbsolutePath, + expectedSignature: XCFrameworkSignature? = nil, + condition: PlatformCondition? + ) throws -> TargetDependency { let status: LinkingStatus = .required switch path.fileExtension { case .framework: return .framework(path: path, status: status, condition: condition) case .xcframework: - return .xcframework(path: path, expectedSignature: expectedSignature ?? .unsigned, status: status, condition: condition) + return .xcframework( + path: path, + expectedSignature: expectedSignature ?? .unsigned, + status: status, + condition: condition + ) case .dynamicLibrary, .textBasedDynamicLibrary, .staticLibrary: return .library( path: path, diff --git a/Sources/XcodeMetadata/Providers/XCFrameworkMetadataProvider.swift b/Sources/XcodeMetadata/Providers/XCFrameworkMetadataProvider.swift index e8e2121f..da38de01 100644 --- a/Sources/XcodeMetadata/Providers/XCFrameworkMetadataProvider.swift +++ b/Sources/XcodeMetadata/Providers/XCFrameworkMetadataProvider.swift @@ -51,7 +51,7 @@ public protocol XCFrameworkMetadataProviding: PrecompiledMetadataProviding { /// Loads all the metadata associated with an XCFramework at the specified path, and expected signature if signed /// - Note: This performs various shell calls and disk operations - func loadMetadata(at path: AbsolutePath, expectedSignature: XCFrameworkSignature?, status: LinkingStatus) async throws + func loadMetadata(at path: AbsolutePath, expectedSignature: XCFrameworkSignature?, status: LinkingStatus) async throws -> XCFrameworkMetadata /// Returns the info.plist of the xcframework at the given path. From f70304116b9cee6fc964a1830ecefe26f3ea5493 Mon Sep 17 00:00:00 2001 From: Pedro Date: Wed, 30 Apr 2025 11:34:19 +0200 Subject: [PATCH 3/3] Make the tests compile and pass --- Package.resolved | 18 +++++++++--------- Package.swift | 2 +- .../TargetDependencyExtensionsTests.swift | 7 ++++++- .../Models/TargetDependencyTests.swift | 7 ++++++- .../XCFrameworkMetadataProviderTests.swift | 6 +++--- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Package.resolved b/Package.resolved index 08a456d1..363cdd53 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "6e9c67eb028efd58882f60208b868c006b6ab0a4c7006e49085a4c346df383b0", + "originHash" : "d4f68e752993519aee6ad2c355139fa210271f229b5503b0a029f07f61d7b15c", "pins" : [ { "identity" : "aexml", @@ -33,8 +33,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/tuist/FileSystem.git", "state" : { - "revision" : "1bff6d54e90a79706a4a9d77cd081104de430361", - "version" : "0.7.7" + "revision" : "eb33ba606c2d988a6f7247e3fc23faa681d75028", + "version" : "0.7.16" } }, { @@ -51,8 +51,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Kolos65/Mockable.git", "state" : { - "revision" : "203336d0ccb7ff03a8a03db54a4fa18fc2b0c771", - "version" : "0.3.0" + "revision" : "68f3ed6c4b62afab27a84425494cb61421a61ac1", + "version" : "0.3.1" } }, { @@ -123,8 +123,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log", "state" : { - "revision" : "96a2f8a0fa41e9e09af4585e2724c4e825410b91", - "version" : "1.6.2" + "revision" : "3d8596ed08bd13520157f0355e35caed215ffbfa", + "version" : "1.6.3" } }, { @@ -132,8 +132,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio", "state" : { - "revision" : "c51907a839e63ebf0ba2076bba73dd96436bd1b9", - "version" : "2.81.0" + "revision" : "0f54d58bb5db9e064f332e8524150de379d1e51c", + "version" : "2.82.1" } }, { diff --git a/Package.swift b/Package.swift index 3ea83538..cf20eff2 100644 --- a/Package.swift +++ b/Package.swift @@ -84,7 +84,7 @@ let package = Package( .package(url: "https://github.com/tuist/Command.git", from: "0.13.0"), .package(url: "https://github.com/tuist/FileSystem.git", .upToNextMajor(from: "0.7.9")), .package(url: "https://github.com/apple/swift-service-context", .upToNextMajor(from: "1.2.0")), - .package(url: "https://github.com/Kolos65/Mockable.git", .upToNextMajor(from: "0.3.0")), + .package(url: "https://github.com/Kolos65/Mockable.git", .upToNextMajor(from: "0.3.1")), .package(url: "https://github.com/p-x9/MachOKit", .upToNextMajor(from: "0.30.0")), .package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.4.3"), ], diff --git a/Tests/XcodeGraphMapperTests/MapperTests/Target/TargetDependencyExtensionsTests.swift b/Tests/XcodeGraphMapperTests/MapperTests/Target/TargetDependencyExtensionsTests.swift index 636ee8a8..9f1336bc 100644 --- a/Tests/XcodeGraphMapperTests/MapperTests/Target/TargetDependencyExtensionsTests.swift +++ b/Tests/XcodeGraphMapperTests/MapperTests/Target/TargetDependencyExtensionsTests.swift @@ -83,7 +83,12 @@ struct TargetDependencyExtensionsTests { func testTargetGraphDependency_XCFramework() async throws { // Given let xcframeworkPath = sourceDirectory.appending(component: "MyFramework.xcframework") - let dependency = TargetDependency.xcframework(path: xcframeworkPath, status: .required, condition: nil) + let dependency = TargetDependency.xcframework( + path: xcframeworkPath, + expectedSignature: nil, + status: .required, + condition: nil + ) // When let graphDep = try await dependency.graphDependency( diff --git a/Tests/XcodeGraphTests/Models/TargetDependencyTests.swift b/Tests/XcodeGraphTests/Models/TargetDependencyTests.swift index 0cf1d5d9..e3a070a7 100644 --- a/Tests/XcodeGraphTests/Models/TargetDependencyTests.swift +++ b/Tests/XcodeGraphTests/Models/TargetDependencyTests.swift @@ -50,7 +50,12 @@ final class TargetDependencyTests: XCTestCase { .sdk(name: "", status: .required, condition: expected), .package(product: "", type: .plugin, condition: expected), .target(name: "", condition: expected), - .xcframework(path: try! AbsolutePath(validating: "/"), status: .required, condition: expected), + .xcframework( + path: try! AbsolutePath(validating: "/"), + expectedSignature: nil, + status: .required, + condition: expected + ), .project(target: "", path: try! AbsolutePath(validating: "/"), condition: expected), ] diff --git a/Tests/XcodeMetadataTests/XCFrameworkMetadataProviderTests.swift b/Tests/XcodeMetadataTests/XCFrameworkMetadataProviderTests.swift index 37977b63..15390de0 100644 --- a/Tests/XcodeMetadataTests/XCFrameworkMetadataProviderTests.swift +++ b/Tests/XcodeMetadataTests/XCFrameworkMetadataProviderTests.swift @@ -97,7 +97,7 @@ struct XCFrameworkMetadataProviderTests { ) // When - let metadata = try await subject.loadMetadata(at: frameworkPath, status: .required) + let metadata = try await subject.loadMetadata(at: frameworkPath, expectedSignature: nil, status: .required) // Then let expectedInfoPlist = XCFrameworkInfoPlist(libraries: [ @@ -161,7 +161,7 @@ struct XCFrameworkMetadataProviderTests { ) // When - let metadata = try await subject.loadMetadata(at: frameworkPath, status: .required) + let metadata = try await subject.loadMetadata(at: frameworkPath, expectedSignature: nil, status: .required) // Then let expectedInfoPlist = XCFrameworkInfoPlist(libraries: [ @@ -243,7 +243,7 @@ struct XCFrameworkMetadataProviderTests { ) // When - let metadata = try await subject.loadMetadata(at: frameworkPath, status: .required) + let metadata = try await subject.loadMetadata(at: frameworkPath, expectedSignature: nil, status: .required) // Then #expect(metadata.infoPlist.libraries.count == 2, "Libraries count mismatch")