Skip to content

Commit

Permalink
Merge pull request #1 from Shepherd-Dog/feature/handleModuleStability2
Browse files Browse the repository at this point in the history
 Consider module stability when building frameworks
  • Loading branch information
telip007 authored Jan 29, 2020
2 parents 8b34a90 + d1f4850 commit aef25a3
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 2 deletions.
26 changes: 25 additions & 1 deletion Source/CarthageKit/Xcode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,36 @@ internal func isSwiftFramework(_ frameworkURL: URL) -> Bool {
internal func checkSwiftFrameworkCompatibility(_ frameworkURL: URL, usingToolchain toolchain: String?) -> SignalProducer<URL, SwiftVersionError> {
return SignalProducer.combineLatest(swiftVersion(usingToolchain: toolchain), frameworkSwiftVersion(frameworkURL))
.attemptMap { localSwiftVersion, frameworkSwiftVersion in
return localSwiftVersion == frameworkSwiftVersion
return localSwiftVersion == frameworkSwiftVersion || isModuleStableAPI(localSwiftVersion, frameworkSwiftVersion, frameworkURL)
? .success(frameworkURL)
: .failure(.incompatibleFrameworkSwiftVersions(local: localSwiftVersion, framework: frameworkSwiftVersion))
}
}

/// Determines whether a local swift version and a framework combination are considered module stable
internal func isModuleStableAPI(_ localSwiftVersion: String,
_ frameworkSwiftVersion: String,
_ frameworkURL: URL) -> Bool {
guard let localSwiftVersionNumber = determineMajorMinorVersion(localSwiftVersion),
let frameworkSwiftVersionNumber = determineMajorMinorVersion(frameworkSwiftVersion),
let swiftModuleURL = frameworkURL.swiftmoduleURL() else { return false }

let hasSwiftInterfaceFile = try? FileManager.default.contentsOfDirectory(at: swiftModuleURL,
includingPropertiesForKeys: nil,
options: []).first { (url) -> Bool in
return url.lastPathComponent.contains("swiftinterface")
} != nil

return localSwiftVersionNumber >= 5.1 && frameworkSwiftVersionNumber >= 5.1 && hasSwiftInterfaceFile == true
}

/// Attempts to return a `Double` representing the major/minor version components parsed from a given swift version, otherwise returns `nil`.
private func determineMajorMinorVersion(_ swiftVersion: String) -> Double? {
guard let range = swiftVersion.range(of: "^(\\d+)\\.(\\d+)", options: .regularExpression) else { return nil }

return Double(swiftVersion[range])
}

/// Emits the framework URL if it is compatible with the build environment and errors if not.
internal func checkFrameworkCompatibility(_ frameworkURL: URL, usingToolchain toolchain: String?) -> SignalProducer<URL, SwiftVersionError> {
if isSwiftFramework(frameworkURL) {
Expand Down
27 changes: 27 additions & 0 deletions Tests/CarthageKitTests/XcodeSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,33 @@ class XcodeSpec: QuickSpec {

expect(result?.value) == "4.1-dev (LLVM 0fcc19c0d8, Clang 1696f82ad2, Swift 691139445e)"
}

it("should determine when a module-stable Swift framework is incompatible") {
let localSwiftVersion = "5.0 (swiftlang-1001.0.69.5 clang-1001.0.46.3)"
let frameworkVersion = "5.1.2 (swiftlang-1100.0.278 clang-1100.0.33.9)"
let frameworkURL = Bundle(for: type(of: self)).url(forResource: "ModuleStableBuiltWithSwift5.1.2.framework", withExtension: nil)!
let result = isModuleStableAPI(localSwiftVersion, frameworkVersion, frameworkURL)

expect(result).to(beFalse())
}

it("should determine when a non-module-stable Swift framework is incompatible") {
let localSwiftVersion = "5.1 (swiftlang-1100.0.270.13 clang-1100.0.33.7)"
let frameworkVersion = "5.1.2 (swiftlang-1100.0.278 clang-1100.0.33.9)"
let frameworkURL = Bundle(for: type(of: self)).url(forResource: "NonModuleStableBuiltWithSwift5.1.2.framework", withExtension: nil)!
let result = isModuleStableAPI(localSwiftVersion, frameworkVersion, frameworkURL)

expect(result).to(beFalse())
}

it("should determine when a module-stable Swift framework is compatible") {
let localSwiftVersion = "5.1 (swiftlang-1100.0.270.13 clang-1100.0.33.7)"
let frameworkVersion = "5.1.2 (swiftlang-1100.0.278 clang-1100.0.33.9)"
let frameworkURL = Bundle(for: type(of: self)).url(forResource: "ModuleStableBuiltWithSwift5.1.2.framework", withExtension: nil)!
let result = isModuleStableAPI(localSwiftVersion, frameworkVersion, frameworkURL)

expect(result).to(beTrue())
}
}

describe("locateProjectsInDirectory:") {
Expand Down
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion script/copy-fixtures
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fi
current=$(cd "$(dirname $0)" && pwd)
destination="$1"

for fixture in "carthage-fixtures-ReactiveCocoaLayout-master" "CartfileOnly" "CartfilePrivateOnly" "NoCartfile" "SchemeDiscoverySampleForCarthage-0.2" "Swell-0.5.0" "SampleMultipleSubprojects" "SampleGitSubmodule" "DependencyTest" "WorkspaceWithDependency" "DynamicAndStatic" "WorkspaceWithDependency" "FilterBogusFrameworks" "NoSharedSchemesTest" "CleanupTest"
for fixture in "carthage-fixtures-ReactiveCocoaLayout-master" "CartfileOnly" "CartfilePrivateOnly" "NoCartfile" "SchemeDiscoverySampleForCarthage-0.2" "Swell-0.5.0" "SampleMultipleSubprojects" "SampleGitSubmodule" "DependencyTest" "WorkspaceWithDependency" "DynamicAndStatic" "WorkspaceWithDependency" "FilterBogusFrameworks" "NoSharedSchemesTest" "CleanupTest" "ModuleStableBuiltWithSwift5.1.2" "NonModuleStableBuiltWithSwift5.1.2"
do
rm -Rf "$destination/__MACOSX"
rm -Rf "$destination/$fixture"
Expand Down

0 comments on commit aef25a3

Please sign in to comment.