diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsPodspecIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsPodspecIT.kt index fc8dbe64322..9c380b6d3ea 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsPodspecIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsPodspecIT.kt @@ -13,7 +13,7 @@ import kotlin.io.path.readText import kotlin.test.assertEquals @OsCondition(supportedOn = [OS.MAC], enabledOnCI = [OS.MAC]) -@DisplayName("K/N tests with cocoapods' podspec") +@DisplayName("CocoaPods plugin podspec generation tests") @NativeGradlePluginTests class CocoaPodsPodspecIT : KGPBaseTest() { @@ -44,7 +44,7 @@ class CocoaPodsPodspecIT : KGPBaseTest() { cocoapodsMultipleKtPods, gradleVersion, mapOf("kotlin-library" to null, "second-library" to null), - mapOf("kotlin-library" to kotlinLibraryPodspecContent(), "second-library" to secondLibraryPodspecContent("second_library")), + mapOf("kotlin-library" to kotlinLibraryPodspecContent(), "second-library" to secondLibraryPodspecContent()), ) @DisplayName("Build project with two podspecs with custom framework name") @@ -96,7 +96,7 @@ class CocoaPodsPodspecIT : KGPBaseTest() { } } - private fun kotlinLibraryPodspecContent(frameworkName: String? = null) = """ + private fun kotlinLibraryPodspecContent(frameworkName: String = "kotlin_library") = """ Pod::Spec.new do |spec| spec.name = 'kotlin_library' spec.version = '1.0' @@ -105,14 +105,21 @@ class CocoaPodsPodspecIT : KGPBaseTest() { spec.authors = '' spec.license = '' spec.summary = 'CocoaPods test library' - spec.vendored_frameworks = 'build/cocoapods/framework/${frameworkName ?: "kotlin_library"}.framework' + spec.vendored_frameworks = 'build/cocoapods/framework/$frameworkName.framework' spec.libraries = 'c++' spec.ios.deployment_target = '11.0' spec.dependency 'pod_dependency', '1.0' spec.dependency 'subspec_dependency/Core', '1.0' + if !Dir.exist?('build/cocoapods/framework/$frameworkName.framework') || Dir.empty?('build/cocoapods/framework/$frameworkName.framework') + raise " + Kotlin framework '$frameworkName' doesn't exist yet, so a proper Xcode project can't be generated. + 'pod install' should be executed after running ':generateDummyFramework' Gradle task: + ./gradlew :kotlin-library:generateDummyFramework + Alternatively, proper pod installation is performed during Gradle sync in the IDE (if Podfile location is set)" + end spec.pod_target_xcconfig = { 'KOTLIN_PROJECT_PATH' => ':kotlin-library', - 'PRODUCT_MODULE_NAME' => '${frameworkName ?: "kotlin_library"}', + 'PRODUCT_MODULE_NAME' => '$frameworkName', } spec.script_phases = [ { @@ -136,7 +143,7 @@ class CocoaPodsPodspecIT : KGPBaseTest() { end """.trimIndent() - private fun secondLibraryPodspecContent(frameworkName: String? = null) = """ + private fun secondLibraryPodspecContent(frameworkName: String = "second_library") = """ Pod::Spec.new do |spec| spec.name = 'second_library' spec.version = '1.0' @@ -145,11 +152,18 @@ class CocoaPodsPodspecIT : KGPBaseTest() { spec.authors = '' spec.license = '' spec.summary = 'CocoaPods test library' - spec.vendored_frameworks = 'build/cocoapods/framework/${frameworkName ?: "second_library"}.framework' + spec.vendored_frameworks = 'build/cocoapods/framework/$frameworkName.framework' spec.libraries = 'c++' + if !Dir.exist?('build/cocoapods/framework/$frameworkName.framework') || Dir.empty?('build/cocoapods/framework/$frameworkName.framework') + raise " + Kotlin framework '$frameworkName' doesn't exist yet, so a proper Xcode project can't be generated. + 'pod install' should be executed after running ':generateDummyFramework' Gradle task: + ./gradlew :second-library:generateDummyFramework + Alternatively, proper pod installation is performed during Gradle sync in the IDE (if Podfile location is set)" + end spec.pod_target_xcconfig = { 'KOTLIN_PROJECT_PATH' => ':second-library', - 'PRODUCT_MODULE_NAME' => '${frameworkName ?: "kotlin_library"}', + 'PRODUCT_MODULE_NAME' => '$frameworkName', } spec.script_phases = [ { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/tasks/PodspecTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/tasks/PodspecTask.kt index 20c5d1ebb6d..85f35746f8c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/tasks/PodspecTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/tasks/PodspecTask.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -18,7 +18,9 @@ import org.gradle.work.DisableCachingByDefault import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.PodspecPlatformSettings import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin +import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.DUMMY_FRAMEWORK_TASK_NAME import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.GENERATE_WRAPPER_PROPERTY +import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_INSTALL_TASK_NAME import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.SYNC_TASK_NAME import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs import org.jetbrains.kotlin.gradle.utils.getFile @@ -132,7 +134,22 @@ abstract class PodspecTask @Inject constructor(private val projectLayout: Projec val frameworkDir = projectLayout.cocoapodsBuildDirs.framework.getFile().relativeTo(outputFile.parentFile) val vendoredFramework = if (publishing.get()) "${frameworkName.get()}.xcframework" else frameworkDir.resolve("${frameworkName.get()}.framework").invariantSeparatorsPath - val vendoredFrameworks = if (extraSpecAttributes.get().containsKey("vendored_frameworks")) "" else "| spec.vendored_frameworks = '$vendoredFramework'" + val vendoredFrameworksOverridden = extraSpecAttributes.get().containsKey("vendored_frameworks") + val vendoredFrameworks = if (vendoredFrameworksOverridden) "" else "| spec.vendored_frameworks = '$vendoredFramework'" + + val vendoredFrameworkExistenceCheck = if (vendoredFrameworksOverridden || publishing.get()) "" else + """ | + | if !Dir.exist?('$vendoredFramework') || Dir.empty?('$vendoredFramework') + | raise " + | + | Kotlin framework '${frameworkName.get()}' doesn't exist yet, so a proper Xcode project can't be generated. + | 'pod install' should be executed after running ':$DUMMY_FRAMEWORK_TASK_NAME' Gradle task: + | + | ./gradlew ${projectPath.get()}:$DUMMY_FRAMEWORK_TASK_NAME + | + | Alternatively, proper pod installation is performed during Gradle sync in the IDE (if Podfile location is set)" + | end + """.trimMargin() val libraries = if (extraSpecAttributes.get().containsKey("libraries")) "" else "| spec.libraries = 'c++'" @@ -184,6 +201,7 @@ abstract class PodspecTask @Inject constructor(private val projectLayout: Projec $libraries $deploymentTargets $dependencies + $vendoredFrameworkExistenceCheck $xcConfig $scriptPhase $customSpec