Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a xcframework dependency type #769

Merged

Conversation

lakpa
Copy link
Contributor

@lakpa lakpa commented Dec 8, 2019

Short description 📝

This PR introduces a new dependency type to support xcframework.

Solution 📦

A graph node to represent xcframework dependency called XCFrameworkNode is introduced which inherits from PrecompiledNode, the XCframeworkNode can leverage existing lookup however the only exception we need to consider is during embedding phase when we need to specifically look for xcframework file type to skip getting the xcframework being picked up as precompiled to skip embed script build phase and embed the respective file reference with required CodeSignOnCopy attribute instead.

@lakpa lakpa force-pushed the feature/introduction-xcframework-dependency-type branch from 5a2069f to 0cdf13f Compare December 9, 2019 21:30
@lakpa lakpa force-pushed the feature/introduction-xcframework-dependency-type branch from 0cdf13f to 9c21445 Compare December 9, 2019 21:33
Copy link
Collaborator

@kwridan kwridan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good @lakpa 👍

some final bits:

import Foundation
import XCTest

@testable import xcframeworks
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: @testable import App

Comment on lines 96 to 114
let pbxproj = PBXProj()
let pbxTarget = PBXNativeTarget(name: "Test")
let sourceRootPath = AbsolutePath("/")

let group = PBXGroup()
pbxproj.add(object: group)

let from = AbsolutePath("/Frameworks/")
let fileAbsolutePath = AbsolutePath("/Frameworks/Test.xcframework")
let fileRelativePath = RelativePath("./Test.xcframework")
let fileElements = ProjectFileElements()
fileElements.addFileElement(from: from,
fileAbsolutePath: fileAbsolutePath,
fileRelativePath: fileRelativePath,
name: nil,
toGroup: group,
pbxproj: pbxproj)

let wakaFile = fileElements.file(path: fileAbsolutePath)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can benefit from a test helper here to make the test more concise.

// Given
let xcframeworkPath = AbsolutePath("/Frameworks/Test.xcframework")
let dependencies: [DependencyReference] = [
  .absolute(xcframeworkPath)
]
let fileElements = createFileElements(for: xcframeworkPath)
// ...

Note: "waka" was the name of a framework used in another test, there is no need to use it here as the framework we have here is called "test", the name doesn't really impact the test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, we could make code concise by using a helper.

// Given
let library = LibraryNode.test()
let framework = FrameworkNode.test()
let cocoapods = CocoaPodsNode.test()
let xcframework = try XCFrameworkNode.test()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this helper exist? is there a reason it's throwing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for spotting, i was running some trials, it got left over after. Will remove it.

Comment on lines 124 to 129
let copyBuildPhase: PBXCopyFilesBuildPhase? = pbxTarget.buildPhases.last as? PBXCopyFilesBuildPhase
XCTAssertEqual(copyBuildPhase?.name, "Embed Frameworks")
let wakaBuildFile: PBXBuildFile? = copyBuildPhase?.files?.last
XCTAssertEqual(wakaBuildFile?.file, wakaFile)
let settings: [String: [String]]? = wakaBuildFile?.settings as? [String: [String]]
XCTAssertEqual(settings, ["ATTRIBUTES": ["CodeSignOnCopy"]])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here we could benefit from some array comparisons to make the asserts more readable

(this is somewhat subjective)

       // Then
        let copyBuildPhase = try XCTUnwrap(pbxTarget.embedFrameworksBuildPhases().first)
        let buildFiles = try XCTUnwrap(copyBuildPhase.files)
        XCTAssertEqual(buildFiles.map { $0.file?.path }, [
            "Test.xcframework"
        ])
        XCTAssertEqual(buildFiles.map { $0.settings as? [String: [String]] }, [
            ["ATTRIBUTES": ["CodeSignOnCopy"]]
        ])

@lakpa lakpa force-pushed the feature/introduction-xcframework-dependency-type branch from 0cc6b9d to 5f6241a Compare December 9, 2019 22:58
@@ -169,7 +169,19 @@ final class LinkGenerator: LinkGenerating {

try dependencies.forEach { dependency in
if case let GraphDependencyReference.absolute(path) = dependency {
precompiledFrameworkPaths.append(path)
if path.extension == "xcframework" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

@@ -88,6 +88,39 @@ final class LinkGeneratorErrorTests: XCTestCase {
XCTAssertEqual($0 as? LinkGeneratorError, LinkGeneratorError.missingProduct(name: "Test"))
}
}

func test_generateEmbedPhase_setupEmbedFrameworksBuildPhase_whenXCFrameworkIsPresent() throws {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beautifully tested 👏

@@ -230,3 +230,11 @@ Scenario: The project is an iOS application with watch app (ios_app_with_watchap
Then I should be able to build for watchOS the scheme App
Then the product 'App.app' with destination 'Debug-iphoneos' contains resource 'Watch/WatchApp.app'
Then the product 'WatchApp.app' with destination 'Debug-watchos' contains extension 'WatchAppExtension'

Scenario: The project is an iOS application with Xcframeworks (ios_app_with_xcframeworks)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Xcframeworks -> xcframeworks

Copy link
Contributor

@pepicrft pepicrft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @lakpa! Just wanted to say you did an amazing job here 👏. I'm very excited about seeing xcframeworks' support landing in the project.

@lakpa
Copy link
Contributor Author

lakpa commented Dec 10, 2019

Hey @lakpa! Just wanted to say you did an amazing job here 👏. I'm very excited about seeing xcframeworks' support landing in the project.

Could manage to do with guidance from you and @kwridan , thanks for your guidance!!!

@lakpa lakpa requested a review from kwridan December 10, 2019 10:37
@lakpa
Copy link
Contributor Author

lakpa commented Dec 10, 2019

  • Worth adding a static library xcframework fixture too

@kwridan , wondering if I could include the static lib fixture in next PR as follow up work is needed to support static libs, which hasn't accounted in this PR in regards to binary path.

@lakpa lakpa force-pushed the feature/introduction-xcframework-dependency-type branch from 5f6241a to 8d5344a Compare December 10, 2019 11:24
Copy link
Collaborator

@kwridan kwridan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, thanks for all the updates @lakpa

@@ -482,4 +515,19 @@ final class LinkGeneratorErrorTests: XCTestCase {

return projectFileElements
}

private func createFileElements(fileAbsolutePath: AbsolutePath,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome! thanks for making this helper 👍

One last suggestion to simplify it even further, we can prime the ProjectFileElements directly with the fileElement.

 private func createFileElements(fileAbsolutePath: AbsolutePath) -> ProjectFileElements {
        let fileElements = ProjectFileElements()
        fileElements.elements[fileAbsolutePath] = PBXFileReference(path: fileAbsolutePath.basename)
        return fileElements
    }

Something like this makes it an even more re-usable helper here as it not specific to the Test.xcframework

XCTAssertEqual(buildFiles.map { $0.settings as? [String: [String]] }, [
["ATTRIBUTES": ["CodeSignOnCopy"]]
])
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@lakpa lakpa force-pushed the feature/introduction-xcframework-dependency-type branch from 5778923 to 44dca72 Compare December 11, 2019 20:38
@lakpa lakpa merged commit 0ac8004 into tuist:master Dec 11, 2019
@lakpa lakpa deleted the feature/introduction-xcframework-dependency-type branch December 11, 2019 20:47
@kwridan kwridan mentioned this pull request Dec 17, 2019
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants