diff --git a/Sources/ProjectSpec/SpecValidation.swift b/Sources/ProjectSpec/SpecValidation.swift index 7370dc18..d223ae96 100644 --- a/Sources/ProjectSpec/SpecValidation.swift +++ b/Sources/ProjectSpec/SpecValidation.swift @@ -163,6 +163,9 @@ extension Project { if getProjectReference(dependencyProjectName) == nil { errors.append(.invalidTargetDependency(target: target.name, dependency: dependency.reference)) } + case .package: + // Package depedency should be located in `package:`, not `target:` + errors.append(.invalidPackageDependencyReference(name: target.name)) } case .sdk: let path = Path(dependency.reference) @@ -243,7 +246,9 @@ extension Project { return .invalidSchemeTarget(scheme: scheme.name, target: targetReference.name, action: action) case .project(let project) where getProjectReference(project) == nil: return .invalidProjectReference(scheme: scheme.name, reference: project) - case .local, .project: + case .package(let package) where getPackage(targetReference.name) == nil: + return .invalidSwiftPackage(name: targetReference.name, target: package) + case .local, .project, .package: return nil } } diff --git a/Sources/ProjectSpec/SpecValidationError.swift b/Sources/ProjectSpec/SpecValidationError.swift index c1948652..f4025bbf 100644 --- a/Sources/ProjectSpec/SpecValidationError.swift +++ b/Sources/ProjectSpec/SpecValidationError.swift @@ -20,6 +20,7 @@ public struct SpecValidationError: Error, CustomStringConvertible { case invalidSchemeTarget(scheme: String, target: String, action: String) case invalidSchemeConfig(scheme: String, config: String) case invalidSwiftPackage(name: String, target: String) + case invalidPackageDependencyReference(name: String) case invalidLocalPackage(String) case invalidConfigFile(configFile: String, config: String) case invalidBuildSettingConfig(String) @@ -69,6 +70,8 @@ public struct SpecValidationError: Error, CustomStringConvertible { return "Target \(target.quoted) has an invalid package dependency \(name.quoted)" case let .invalidLocalPackage(path): return "Invalid local package \(path.quoted)" + case let .invalidPackageDependencyReference(name): + return "Package reference \(name) must be specified as package dependency, not target" case let .missingConfigForTargetScheme(target, configType): return "Target \(target.quoted) is missing a config of type \(configType.rawValue) to generate its scheme" case let .missingDefaultConfig(name): diff --git a/Sources/ProjectSpec/TargetReference.swift b/Sources/ProjectSpec/TargetReference.swift index ecec50cb..f75a8494 100644 --- a/Sources/ProjectSpec/TargetReference.swift +++ b/Sources/ProjectSpec/TargetReference.swift @@ -8,6 +8,7 @@ public struct TargetReference: Hashable { public enum Location: Hashable { case local case project(String) + case package(String) } public init(name: String, location: Location) { @@ -46,8 +47,8 @@ extension TargetReference: CustomStringConvertible { public var reference: String { switch location { case .local: return name - case .project(let projectPath): - return "\(projectPath)/\(name)" + case .project(let root), .package(let root): + return "\(root)/\(name)" } } @@ -74,6 +75,8 @@ extension TargetReference: JSONEncodable { public func toJSONValue() -> Any { var dictionary: JSONDictionary = [:] switch self.location { + case .package(let packageName): + dictionary["package"] = "\(packageName)/\(name)" case .project(let projectName): dictionary["project"] = "\(projectName)/\(name)" case .local: diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 9b4f8097..887069dd 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -763,6 +763,10 @@ public class PBXProjGenerator { let (targetDependency, dependencyTarget, dependencyProductProxy) = try generateExternalTargetDependency(from: target.name, to: dependencyTargetName, in: dependencyProjectName, platform: target.platform) dependencies.append(targetDependency) processTargetDependency(dependency, dependencyTarget: dependencyTarget, embedFileReference: dependencyProductProxy) + case .package: + // Specifying as package dependency as target is not allowed. + // This should be validated at SpecValidation part. + fatalError("Package dependency should not be added as target dependency") } case .framework: @@ -1412,6 +1416,10 @@ public class PBXProjGenerator { if isTopLevel || dependency.embed != true { dependencies[dependency.uniqueID] = dependency } + case .package: + // Specifying as package dependency as target is not allowed. + // This should be validated at SpecValidation part. + fatalError("Package dependency should not be added as target dependency") } case .bundle: if isTopLevel { diff --git a/Sources/XcodeGenKit/SchemeGenerator.swift b/Sources/XcodeGenKit/SchemeGenerator.swift index f9f718a8..e0d86fe7 100644 --- a/Sources/XcodeGenKit/SchemeGenerator.swift +++ b/Sources/XcodeGenKit/SchemeGenerator.swift @@ -110,6 +110,16 @@ public class SchemeGenerator { case .local: pbxProj = self.pbxProj projectFilePath = "\(self.project.name).xcodeproj" + case .package(let packageName): + guard let package = self.project.getPackage(packageName), case .local(let path) = package else { + throw SchemeGenerationError.missingPackage(packageName) + } + return XCScheme.BuildableReference( + referencedContainer: "container:\(path)", + blueprintIdentifier: target.name, + buildableName: target.name, + blueprintName: target.name + ) } guard let pbxTarget = pbxProj.targets(named: target.name).first else { @@ -127,6 +137,8 @@ public class SchemeGenerator { fatalError("Unable to determinate \"buildableName\" for build target: \(target)") } buildableName = _buildableName + case .package: // all `package` target should be handled above + fatalError("unexpected package target is handled") } return XCScheme.BuildableReference( @@ -142,32 +154,12 @@ public class SchemeGenerator { return XCScheme.BuildAction.Entry(buildableReference: buildableReference, buildFor: buildTarget.buildTypes) } - func getBuildEntryForTestTarget(_ buildTarget: Scheme.BuildTarget) throws -> XCScheme.BuildAction.Entry { - - // Need to check local Swift Package test case - func getBuildableReferenceForSPM(_ target: TargetReference) -> XCScheme.BuildableReference? { - if case .project(let project) = target.location, - let package = self.project.getPackage(project), case .local(let path) = package { - return XCScheme.BuildableReference( - referencedContainer: "container:\(path)", - blueprintIdentifier: target.name, - buildableName: target.name, - blueprintName: target.name - ) - } else { - return nil - } - } - let buildableReference = try getBuildableReferenceForSPM(buildTarget.target) ?? getBuildableReference(buildTarget.target) - return XCScheme.BuildAction.Entry(buildableReference: buildableReference, buildFor: buildTarget.buildTypes) - } - let testTargets = scheme.test?.targets ?? [] let testBuildTargets = testTargets.map { Scheme.BuildTarget(target: $0.targetReference, buildTypes: BuildType.testOnly) } - let testBuildTargetEntries = try testBuildTargets.map(getBuildEntryForTestTarget) + let testBuildTargetEntries = try testBuildTargets.map(getBuildEntry) let buildActionEntries: [XCScheme.BuildAction.Entry] = try scheme.build.targets.map(getBuildEntry) @@ -378,6 +370,7 @@ public class SchemeGenerator { enum SchemeGenerationError: Error, CustomStringConvertible { case missingTarget(TargetReference, projectPath: String) + case missingPackage(String) case missingProject(String) case missingBuildTargets(String) @@ -389,6 +382,8 @@ enum SchemeGenerationError: Error, CustomStringConvertible { return "Unable to find project reference named \"\(project)\" in project.yml" case .missingBuildTargets(let name): return "Unable to find at least one build target in scheme \"\(name)\"" + case .missingPackage(let package): + return "Unable to find swift package named \"\(package)\" in project.yml" } } }