[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)
|
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
|
@Test
|
||||||
fun basicUTDTest() {
|
fun basicUTDTest() {
|
||||||
val tasks = listOf(
|
val tasks = listOf(
|
||||||
@@ -771,10 +840,10 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
fun testUseDynamicFramework() {
|
fun testUseDynamicFramework() {
|
||||||
with(project) {
|
with(project) {
|
||||||
gradleBuildScript().addPod(defaultPodName, produceGitBlock(defaultPodRepo))
|
gradleBuildScript().addPod(defaultPodName, produceGitBlock(defaultPodRepo))
|
||||||
gradleBuildScript().appendToFrameworkBlock("isStatic=false")
|
gradleBuildScript().appendToFrameworkBlock("isStatic = false")
|
||||||
hooks.addHook {
|
hooks.addHook {
|
||||||
// Check that an output framework is a dynamic framework
|
// 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())) {
|
with(runProcess(listOf("file", framework.absolutePath), projectDir, environmentVariables = getEnvs())) {
|
||||||
assertTrue(isSuccessful)
|
assertTrue(isSuccessful)
|
||||||
assertTrue(output.contains("dynamically linked shared library"))
|
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
|
@Test
|
||||||
fun testCocoapodsWithRegularFrameworkDefinition() {
|
fun testCocoapodsWithRegularFrameworkDefinition() {
|
||||||
with(project) {
|
with(project) {
|
||||||
|
|||||||
+1
-1
@@ -121,7 +121,7 @@ abstract class CocoapodsExtension @Inject constructor(private val project: Proje
|
|||||||
anyFramework
|
anyFramework
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val podFrameworkName = anyPodFramework.map { it.baseName }
|
internal val podFrameworkName = anyPodFramework.map { it.baseName.asValidFrameworkName() }
|
||||||
internal val podFrameworkIsStatic = anyPodFramework.map { it.isStatic }
|
internal val podFrameworkIsStatic = anyPodFramework.map { it.isStatic }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+14
-12
@@ -53,6 +53,9 @@ internal class CocoapodsBuildDirs(val project: Project) {
|
|||||||
val framework: File
|
val framework: File
|
||||||
get() = root.resolve("framework")
|
get() = root.resolve("framework")
|
||||||
|
|
||||||
|
val dummyFramework: File
|
||||||
|
get() = root.resolve("dummy.framework")
|
||||||
|
|
||||||
val defs: File
|
val defs: File
|
||||||
get() = root.resolve("defs")
|
get() = root.resolve("defs")
|
||||||
|
|
||||||
@@ -365,9 +368,9 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
project: Project,
|
project: Project,
|
||||||
cocoapodsExtension: CocoapodsExtension
|
cocoapodsExtension: CocoapodsExtension
|
||||||
) {
|
) {
|
||||||
project.tasks.register(DUMMY_FRAMEWORK_TASK_NAME, DummyFrameworkTask::class.java) {
|
project.registerTask<DummyFrameworkTask>(DUMMY_FRAMEWORK_TASK_NAME) { task ->
|
||||||
it.frameworkName = cocoapodsExtension.podFrameworkName
|
task.frameworkName.set(cocoapodsExtension.podFrameworkName)
|
||||||
it.useDynamicFramework = cocoapodsExtension.podFrameworkIsStatic.map { isStatic -> !isStatic }
|
task.useStaticFramework.set(cocoapodsExtension.podFrameworkIsStatic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,8 +378,6 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
project: Project,
|
project: Project,
|
||||||
cocoapodsExtension: CocoapodsExtension
|
cocoapodsExtension: CocoapodsExtension
|
||||||
) {
|
) {
|
||||||
val dummyFrameworkTaskProvider = project.tasks.named(DUMMY_FRAMEWORK_TASK_NAME)
|
|
||||||
|
|
||||||
project.tasks.register(POD_SPEC_TASK_NAME, PodspecTask::class.java) {
|
project.tasks.register(POD_SPEC_TASK_NAME, PodspecTask::class.java) {
|
||||||
it.group = TASK_GROUP
|
it.group = TASK_GROUP
|
||||||
it.description = "Generates a podspec file for CocoaPods import"
|
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.osx = project.provider { cocoapodsExtension.osx }
|
||||||
it.tvos = project.provider { cocoapodsExtension.tvos }
|
it.tvos = project.provider { cocoapodsExtension.tvos }
|
||||||
it.watchos = project.provider { cocoapodsExtension.watchos }
|
it.watchos = project.provider { cocoapodsExtension.watchos }
|
||||||
it.dependsOn(dummyFrameworkTaskProvider)
|
|
||||||
val generateWrapper = project.findProperty(GENERATE_WRAPPER_PROPERTY)?.toString()?.toBoolean() ?: false
|
val generateWrapper = project.findProperty(GENERATE_WRAPPER_PROPERTY)?.toString()?.toBoolean() ?: false
|
||||||
if (generateWrapper) {
|
if (generateWrapper) {
|
||||||
it.dependsOn(":wrapper")
|
it.dependsOn(":wrapper")
|
||||||
@@ -461,6 +461,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
cocoapodsExtension: CocoapodsExtension
|
cocoapodsExtension: CocoapodsExtension
|
||||||
) {
|
) {
|
||||||
val podspecTaskProvider = project.tasks.named<PodspecTask>(POD_SPEC_TASK_NAME)
|
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 ->
|
project.registerTask<PodInstallTask>(POD_INSTALL_TASK_NAME) { task ->
|
||||||
task.group = TASK_GROUP
|
task.group = TASK_GROUP
|
||||||
task.description = "Invokes `pod install` call within Podfile location directory"
|
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.frameworkName.set(cocoapodsExtension.podFrameworkName)
|
||||||
task.specRepos.set(project.provider { cocoapodsExtension.specRepos })
|
task.specRepos.set(project.provider { cocoapodsExtension.specRepos })
|
||||||
task.pods.set(cocoapodsExtension.pods)
|
task.pods.set(cocoapodsExtension.pods)
|
||||||
|
task.dummyFramework.set(dummyFrameworkTaskProvider.map { it.outputFramework.get() })
|
||||||
task.dependsOn(podspecTaskProvider)
|
task.dependsOn(podspecTaskProvider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -496,12 +498,12 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
|
|
||||||
val podGenTask = project.registerTask<PodGenTask>(family.toPodGenTaskName) { task ->
|
val podGenTask = project.registerTask<PodGenTask>(family.toPodGenTaskName) { task ->
|
||||||
task.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
|
task.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
|
||||||
task.podspec = podspecTaskProvider.map { it.outputFile }
|
task.podspec.set(podspecTaskProvider.map { it.outputFile })
|
||||||
task.podName = project.provider { cocoapodsExtension.name }
|
task.podName.set(project.provider { cocoapodsExtension.name })
|
||||||
task.useLibraries = project.provider { cocoapodsExtension.useLibraries }
|
task.useLibraries.set(project.provider { cocoapodsExtension.useLibraries })
|
||||||
task.specRepos = project.provider { cocoapodsExtension.specRepos }
|
task.specRepos.set(project.provider { cocoapodsExtension.specRepos })
|
||||||
task.family = family
|
task.family.set(family)
|
||||||
task.platformSettings = platformSettings
|
task.platformSettings.set(platformSettings)
|
||||||
task.pods.set(cocoapodsExtension.pods)
|
task.pods.set(cocoapodsExtension.pods)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-1
@@ -56,6 +56,7 @@ abstract class AbstractPodInstallTask : CocoapodsTask() {
|
|||||||
@get:InputFile
|
@get:InputFile
|
||||||
abstract val podfile: Property<File?>
|
abstract val podfile: Property<File?>
|
||||||
|
|
||||||
|
@get:Internal
|
||||||
protected val workingDir: Provider<File> = podfile.map { file: File? ->
|
protected val workingDir: Provider<File> = podfile.map { file: File? ->
|
||||||
requireNotNull(file) { "Task outputs shouldn't be queried if it's skipped" }.parentFile
|
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() {
|
abstract class PodInstallTask : AbstractPodInstallTask() {
|
||||||
|
|
||||||
|
|
||||||
@get:Optional
|
@get:Optional
|
||||||
@get:InputFile
|
@get:InputFile
|
||||||
abstract val podspec: Property<File?>
|
abstract val podspec: Property<File?>
|
||||||
@@ -106,6 +106,32 @@ abstract class PodInstallTask : AbstractPodInstallTask() {
|
|||||||
@get:Nested
|
@get:Nested
|
||||||
abstract val pods: ListProperty<CocoapodsDependency>
|
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? {
|
override fun handleError(retCode: Int, error: String, process: Process): String? {
|
||||||
val specReposMessages = MissingSpecReposMessage(specRepos.get()).missingMessage
|
val specReposMessages = MissingSpecReposMessage(specRepos.get()).missingMessage
|
||||||
val cocoapodsMessages = pods.get().map { MissingCocoapodsMessage(it).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
|
* 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.
|
* and then replace it with the real one during a real build process.
|
||||||
*/
|
*/
|
||||||
open class DummyFrameworkTask : DefaultTask() {
|
abstract class DummyFrameworkTask : DefaultTask() {
|
||||||
|
|
||||||
@OutputDirectory
|
@get:Input
|
||||||
val destinationDir = project.cocoapodsBuildDirs.framework
|
abstract val frameworkName: Property<String>
|
||||||
|
|
||||||
@Input
|
@get:Input
|
||||||
lateinit var frameworkName: Provider<String>
|
abstract val useStaticFramework: Property<Boolean>
|
||||||
|
|
||||||
@Input
|
@get:OutputDirectory
|
||||||
lateinit var useDynamicFramework: Provider<Boolean>
|
val outputFramework: Provider<File> = project.provider { project.cocoapodsBuildDirs.dummyFramework }
|
||||||
|
|
||||||
private val frameworkDir: File
|
private val dummyFrameworkResource: String
|
||||||
get() = destinationDir.resolve("${frameworkName.get()}.framework")
|
|
||||||
|
|
||||||
private val dummyFrameworkPath: String
|
|
||||||
get() {
|
get() {
|
||||||
val staticOrDynamic = if (useDynamicFramework.get()) "dynamic" else "static"
|
val staticOrDynamic = if (!useStaticFramework.get()) "dynamic" else "static"
|
||||||
return "/cocoapods/$staticOrDynamic/dummy.framework/"
|
return "/cocoapods/$staticOrDynamic/dummy.framework/"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyResource(from: String, to: File) {
|
private fun copyResource(from: String, to: File) {
|
||||||
to.parentFile.mkdirs()
|
to.parentFile.mkdirs()
|
||||||
to.outputStream().use { file ->
|
to.outputStream().use { file ->
|
||||||
javaClass.getResourceAsStream(from).use { resource ->
|
javaClass.getResourceAsStream(from)!!.use { resource ->
|
||||||
resource.copyTo(file)
|
resource.copyTo(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,7 +265,7 @@ open class DummyFrameworkTask : DefaultTask() {
|
|||||||
private fun copyTextResource(from: String, to: File, transform: (String) -> String = { it }) {
|
private fun copyTextResource(from: String, to: File, transform: (String) -> String = { it }) {
|
||||||
to.parentFile.mkdirs()
|
to.parentFile.mkdirs()
|
||||||
to.printWriter().use { file ->
|
to.printWriter().use { file ->
|
||||||
javaClass.getResourceAsStream(from).use {
|
javaClass.getResourceAsStream(from)!!.use {
|
||||||
it.reader().forEachLine { str ->
|
it.reader().forEachLine { str ->
|
||||||
file.println(transform(str))
|
file.println(transform(str))
|
||||||
}
|
}
|
||||||
@@ -278,8 +275,8 @@ open class DummyFrameworkTask : DefaultTask() {
|
|||||||
|
|
||||||
private fun copyFrameworkFile(relativeFrom: String, relativeTo: String = relativeFrom) =
|
private fun copyFrameworkFile(relativeFrom: String, relativeTo: String = relativeFrom) =
|
||||||
copyResource(
|
copyResource(
|
||||||
"$dummyFrameworkPath$relativeFrom",
|
"$dummyFrameworkResource$relativeFrom",
|
||||||
frameworkDir.resolve(relativeTo)
|
outputFramework.get().resolve(relativeTo)
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun copyFrameworkTextFile(
|
private fun copyFrameworkTextFile(
|
||||||
@@ -287,15 +284,15 @@ open class DummyFrameworkTask : DefaultTask() {
|
|||||||
relativeTo: String = relativeFrom,
|
relativeTo: String = relativeFrom,
|
||||||
transform: (String) -> String = { it }
|
transform: (String) -> String = { it }
|
||||||
) = copyTextResource(
|
) = copyTextResource(
|
||||||
"$dummyFrameworkPath$relativeFrom",
|
"$dummyFrameworkResource$relativeFrom",
|
||||||
frameworkDir.resolve(relativeTo),
|
outputFramework.get().resolve(relativeTo),
|
||||||
transform
|
transform
|
||||||
)
|
)
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun create() {
|
fun create() {
|
||||||
// Reset the destination directory
|
// Reset the destination directory
|
||||||
with(destinationDir) {
|
with(outputFramework.get()) {
|
||||||
deleteRecursively()
|
deleteRecursively()
|
||||||
mkdirs()
|
mkdirs()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user