[Gradle] Fix invalidating iOS framework after import
^KT-49430 Verification Pending
This commit is contained in:
committed by
Space Team
parent
8a34d1f430
commit
c2e092fe4a
+92
-2
@@ -397,6 +397,75 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
project.testWithWrapper(dummyTaskName)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testImportUTDAfterLinkingFramework() {
|
||||
val linkTaskName = ":linkPodDebugFrameworkIOS"
|
||||
project.gradleBuildScript().appendToCocoapodsBlock("""
|
||||
framework {
|
||||
baseName = "kotlin-library"
|
||||
}
|
||||
name = "kotlin-library"
|
||||
podfile = project.file("ios-app/Podfile")
|
||||
""".trimIndent())
|
||||
|
||||
|
||||
hooks.addHook {
|
||||
assertTasksExecuted(dummyTaskName)
|
||||
assertTasksExecuted(podInstallTaskName)
|
||||
}
|
||||
project.testImport()
|
||||
|
||||
hooks.rewriteHooks {
|
||||
assertTasksExecuted(linkTaskName)
|
||||
}
|
||||
project.testWithWrapper(linkTaskName)
|
||||
|
||||
hooks.rewriteHooks {
|
||||
assertTasksUpToDate(dummyTaskName)
|
||||
assertTasksUpToDate(podInstallTaskName)
|
||||
}
|
||||
project.testImport()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChangeFrameworkTypeUTD() {
|
||||
project.gradleBuildScript().appendToCocoapodsBlock("""
|
||||
framework {
|
||||
baseName = "kotlin-library"
|
||||
}
|
||||
name = "kotlin-library"
|
||||
podfile = project.file("ios-app/Podfile")
|
||||
""".trimIndent())
|
||||
|
||||
hooks.addHook {
|
||||
assertTasksExecuted(dummyTaskName)
|
||||
assertTasksExecuted(podInstallTaskName)
|
||||
}
|
||||
project.testImport()
|
||||
|
||||
hooks.rewriteHooks {
|
||||
assertTasksUpToDate(dummyTaskName)
|
||||
assertTasksUpToDate(podInstallTaskName)
|
||||
}
|
||||
project.testImport()
|
||||
|
||||
project.gradleBuildScript().appendToFrameworkBlock("isStatic = true")
|
||||
|
||||
hooks.rewriteHooks {
|
||||
assertTasksExecuted(dummyTaskName)
|
||||
assertTasksExecuted(podInstallTaskName)
|
||||
}
|
||||
project.testImport()
|
||||
|
||||
hooks.rewriteHooks {
|
||||
assertTasksUpToDate(dummyTaskName)
|
||||
assertTasksUpToDate(podInstallTaskName)
|
||||
}
|
||||
project.testImport()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
fun basicUTDTest() {
|
||||
val tasks = listOf(
|
||||
@@ -771,10 +840,10 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
fun testUseDynamicFramework() {
|
||||
with(project) {
|
||||
gradleBuildScript().addPod(defaultPodName, produceGitBlock(defaultPodRepo))
|
||||
gradleBuildScript().appendToFrameworkBlock("isStatic=false")
|
||||
gradleBuildScript().appendToFrameworkBlock("isStatic = false")
|
||||
hooks.addHook {
|
||||
// Check that an output framework is a dynamic framework
|
||||
val framework = fileInWorkingDir("build/cocoapods/framework/cocoapods.framework/cocoapods")
|
||||
val framework = fileInWorkingDir("build/bin/iOS/podDebugFramework/cocoapods.framework/cocoapods")
|
||||
with(runProcess(listOf("file", framework.absolutePath), projectDir, environmentVariables = getEnvs())) {
|
||||
assertTrue(isSuccessful)
|
||||
assertTrue(output.contains("dynamically linked shared library"))
|
||||
@@ -788,6 +857,27 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUseStaticFramework() {
|
||||
with(project) {
|
||||
gradleBuildScript().addPod(defaultPodName, produceGitBlock(defaultPodRepo))
|
||||
gradleBuildScript().appendToFrameworkBlock("isStatic = true")
|
||||
hooks.addHook {
|
||||
// Check that an output framework is a static framework
|
||||
val framework = fileInWorkingDir("build/bin/iOS/podDebugFramework/cocoapods.framework/cocoapods")
|
||||
with(runProcess(listOf("file", framework.absolutePath), projectDir, environmentVariables = getEnvs())) {
|
||||
assertTrue(isSuccessful)
|
||||
assertTrue(output.contains("current ar archive random library"))
|
||||
}
|
||||
}
|
||||
|
||||
test(
|
||||
"linkPodDebugFrameworkIOS",
|
||||
"-Pkotlin.native.cocoapods.generate.wrapper=true"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCocoapodsWithRegularFrameworkDefinition() {
|
||||
with(project) {
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@ abstract class CocoapodsExtension @Inject constructor(private val project: Proje
|
||||
anyFramework
|
||||
}
|
||||
|
||||
internal val podFrameworkName = anyPodFramework.map { it.baseName }
|
||||
internal val podFrameworkName = anyPodFramework.map { it.baseName.asValidFrameworkName() }
|
||||
internal val podFrameworkIsStatic = anyPodFramework.map { it.isStatic }
|
||||
|
||||
/**
|
||||
|
||||
+14
-12
@@ -53,6 +53,9 @@ internal class CocoapodsBuildDirs(val project: Project) {
|
||||
val framework: File
|
||||
get() = root.resolve("framework")
|
||||
|
||||
val dummyFramework: File
|
||||
get() = root.resolve("dummy.framework")
|
||||
|
||||
val defs: File
|
||||
get() = root.resolve("defs")
|
||||
|
||||
@@ -365,9 +368,9 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
project: Project,
|
||||
cocoapodsExtension: CocoapodsExtension
|
||||
) {
|
||||
project.tasks.register(DUMMY_FRAMEWORK_TASK_NAME, DummyFrameworkTask::class.java) {
|
||||
it.frameworkName = cocoapodsExtension.podFrameworkName
|
||||
it.useDynamicFramework = cocoapodsExtension.podFrameworkIsStatic.map { isStatic -> !isStatic }
|
||||
project.registerTask<DummyFrameworkTask>(DUMMY_FRAMEWORK_TASK_NAME) { task ->
|
||||
task.frameworkName.set(cocoapodsExtension.podFrameworkName)
|
||||
task.useStaticFramework.set(cocoapodsExtension.podFrameworkIsStatic)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,8 +378,6 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
project: Project,
|
||||
cocoapodsExtension: CocoapodsExtension
|
||||
) {
|
||||
val dummyFrameworkTaskProvider = project.tasks.named(DUMMY_FRAMEWORK_TASK_NAME)
|
||||
|
||||
project.tasks.register(POD_SPEC_TASK_NAME, PodspecTask::class.java) {
|
||||
it.group = TASK_GROUP
|
||||
it.description = "Generates a podspec file for CocoaPods import"
|
||||
@@ -396,7 +397,6 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
it.osx = project.provider { cocoapodsExtension.osx }
|
||||
it.tvos = project.provider { cocoapodsExtension.tvos }
|
||||
it.watchos = project.provider { cocoapodsExtension.watchos }
|
||||
it.dependsOn(dummyFrameworkTaskProvider)
|
||||
val generateWrapper = project.findProperty(GENERATE_WRAPPER_PROPERTY)?.toString()?.toBoolean() ?: false
|
||||
if (generateWrapper) {
|
||||
it.dependsOn(":wrapper")
|
||||
@@ -461,6 +461,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
cocoapodsExtension: CocoapodsExtension
|
||||
) {
|
||||
val podspecTaskProvider = project.tasks.named<PodspecTask>(POD_SPEC_TASK_NAME)
|
||||
val dummyFrameworkTaskProvider = project.tasks.named<DummyFrameworkTask>(DUMMY_FRAMEWORK_TASK_NAME)
|
||||
project.registerTask<PodInstallTask>(POD_INSTALL_TASK_NAME) { task ->
|
||||
task.group = TASK_GROUP
|
||||
task.description = "Invokes `pod install` call within Podfile location directory"
|
||||
@@ -469,6 +470,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
task.frameworkName.set(cocoapodsExtension.podFrameworkName)
|
||||
task.specRepos.set(project.provider { cocoapodsExtension.specRepos })
|
||||
task.pods.set(cocoapodsExtension.pods)
|
||||
task.dummyFramework.set(dummyFrameworkTaskProvider.map { it.outputFramework.get() })
|
||||
task.dependsOn(podspecTaskProvider)
|
||||
}
|
||||
}
|
||||
@@ -496,12 +498,12 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
|
||||
val podGenTask = project.registerTask<PodGenTask>(family.toPodGenTaskName) { task ->
|
||||
task.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
|
||||
task.podspec = podspecTaskProvider.map { it.outputFile }
|
||||
task.podName = project.provider { cocoapodsExtension.name }
|
||||
task.useLibraries = project.provider { cocoapodsExtension.useLibraries }
|
||||
task.specRepos = project.provider { cocoapodsExtension.specRepos }
|
||||
task.family = family
|
||||
task.platformSettings = platformSettings
|
||||
task.podspec.set(podspecTaskProvider.map { it.outputFile })
|
||||
task.podName.set(project.provider { cocoapodsExtension.name })
|
||||
task.useLibraries.set(project.provider { cocoapodsExtension.useLibraries })
|
||||
task.specRepos.set(project.provider { cocoapodsExtension.specRepos })
|
||||
task.family.set(family)
|
||||
task.platformSettings.set(platformSettings)
|
||||
task.pods.set(cocoapodsExtension.pods)
|
||||
}
|
||||
|
||||
|
||||
+27
-1
@@ -56,6 +56,7 @@ abstract class AbstractPodInstallTask : CocoapodsTask() {
|
||||
@get:InputFile
|
||||
abstract val podfile: Property<File?>
|
||||
|
||||
@get:Internal
|
||||
protected val workingDir: Provider<File> = podfile.map { file: File? ->
|
||||
requireNotNull(file) { "Task outputs shouldn't be queried if it's skipped" }.parentFile
|
||||
}
|
||||
@@ -92,7 +93,6 @@ abstract class AbstractPodInstallTask : CocoapodsTask() {
|
||||
|
||||
abstract class PodInstallTask : AbstractPodInstallTask() {
|
||||
|
||||
|
||||
@get:Optional
|
||||
@get:InputFile
|
||||
abstract val podspec: Property<File?>
|
||||
@@ -106,6 +106,32 @@ abstract class PodInstallTask : AbstractPodInstallTask() {
|
||||
@get:Nested
|
||||
abstract val pods: ListProperty<CocoapodsDependency>
|
||||
|
||||
@get:InputDirectory
|
||||
abstract val dummyFramework: Property<File>
|
||||
|
||||
private val framework = project.provider { project.cocoapodsBuildDirs.framework.resolve("${frameworkName.get()}.framework") }
|
||||
private val tmpFramework = dummyFramework.map { dummy -> dummy.parentFile.resolve("tmp.framework").also { it.deleteOnExit() } }
|
||||
|
||||
override fun doPodInstall() {
|
||||
// We always need to execute 'pod install' with the dummy framework because the one left from a previous build
|
||||
// may have a wrong linkage type. So we temporarily swap them, run 'pod install' and then swap them back
|
||||
framework.rename(tmpFramework)
|
||||
dummyFramework.rename(framework)
|
||||
super.doPodInstall()
|
||||
framework.rename(dummyFramework)
|
||||
tmpFramework.rename(framework)
|
||||
}
|
||||
|
||||
private fun Provider<File>.rename(dest: Provider<File>) = get().rename(dest.get())
|
||||
|
||||
private fun File.rename(dest: File) {
|
||||
if (!exists()) {
|
||||
mkdirs()
|
||||
}
|
||||
|
||||
check(renameTo(dest)) { "Can't rename '${this}' to '${dest}'" }
|
||||
}
|
||||
|
||||
override fun handleError(retCode: Int, error: String, process: Process): String? {
|
||||
val specReposMessages = MissingSpecReposMessage(specRepos.get()).missingMessage
|
||||
val cocoapodsMessages = pods.get().map { MissingCocoapodsMessage(it).missingMessage }
|
||||
|
||||
+16
-19
@@ -236,30 +236,27 @@ open class PodspecTask : DefaultTask() {
|
||||
* So we create a dummy static framework to allow CocoaPods install our pod correctly
|
||||
* and then replace it with the real one during a real build process.
|
||||
*/
|
||||
open class DummyFrameworkTask : DefaultTask() {
|
||||
abstract class DummyFrameworkTask : DefaultTask() {
|
||||
|
||||
@OutputDirectory
|
||||
val destinationDir = project.cocoapodsBuildDirs.framework
|
||||
@get:Input
|
||||
abstract val frameworkName: Property<String>
|
||||
|
||||
@Input
|
||||
lateinit var frameworkName: Provider<String>
|
||||
@get:Input
|
||||
abstract val useStaticFramework: Property<Boolean>
|
||||
|
||||
@Input
|
||||
lateinit var useDynamicFramework: Provider<Boolean>
|
||||
@get:OutputDirectory
|
||||
val outputFramework: Provider<File> = project.provider { project.cocoapodsBuildDirs.dummyFramework }
|
||||
|
||||
private val frameworkDir: File
|
||||
get() = destinationDir.resolve("${frameworkName.get()}.framework")
|
||||
|
||||
private val dummyFrameworkPath: String
|
||||
private val dummyFrameworkResource: String
|
||||
get() {
|
||||
val staticOrDynamic = if (useDynamicFramework.get()) "dynamic" else "static"
|
||||
val staticOrDynamic = if (!useStaticFramework.get()) "dynamic" else "static"
|
||||
return "/cocoapods/$staticOrDynamic/dummy.framework/"
|
||||
}
|
||||
|
||||
private fun copyResource(from: String, to: File) {
|
||||
to.parentFile.mkdirs()
|
||||
to.outputStream().use { file ->
|
||||
javaClass.getResourceAsStream(from).use { resource ->
|
||||
javaClass.getResourceAsStream(from)!!.use { resource ->
|
||||
resource.copyTo(file)
|
||||
}
|
||||
}
|
||||
@@ -268,7 +265,7 @@ open class DummyFrameworkTask : DefaultTask() {
|
||||
private fun copyTextResource(from: String, to: File, transform: (String) -> String = { it }) {
|
||||
to.parentFile.mkdirs()
|
||||
to.printWriter().use { file ->
|
||||
javaClass.getResourceAsStream(from).use {
|
||||
javaClass.getResourceAsStream(from)!!.use {
|
||||
it.reader().forEachLine { str ->
|
||||
file.println(transform(str))
|
||||
}
|
||||
@@ -278,8 +275,8 @@ open class DummyFrameworkTask : DefaultTask() {
|
||||
|
||||
private fun copyFrameworkFile(relativeFrom: String, relativeTo: String = relativeFrom) =
|
||||
copyResource(
|
||||
"$dummyFrameworkPath$relativeFrom",
|
||||
frameworkDir.resolve(relativeTo)
|
||||
"$dummyFrameworkResource$relativeFrom",
|
||||
outputFramework.get().resolve(relativeTo)
|
||||
)
|
||||
|
||||
private fun copyFrameworkTextFile(
|
||||
@@ -287,15 +284,15 @@ open class DummyFrameworkTask : DefaultTask() {
|
||||
relativeTo: String = relativeFrom,
|
||||
transform: (String) -> String = { it }
|
||||
) = copyTextResource(
|
||||
"$dummyFrameworkPath$relativeFrom",
|
||||
frameworkDir.resolve(relativeTo),
|
||||
"$dummyFrameworkResource$relativeFrom",
|
||||
outputFramework.get().resolve(relativeTo),
|
||||
transform
|
||||
)
|
||||
|
||||
@TaskAction
|
||||
fun create() {
|
||||
// Reset the destination directory
|
||||
with(destinationDir) {
|
||||
with(outputFramework.get()) {
|
||||
deleteRecursively()
|
||||
mkdirs()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user