From 143a233a9e606cce1fd81167ba2eacfa23285ca8 Mon Sep 17 00:00:00 2001 From: Artem Daugel-Dauge Date: Tue, 31 Jan 2023 20:12:57 +0100 Subject: [PATCH] [Gradle] Use unique artifact name for podspec task + avoid redundant task registration ^KT-51518 Verification Pending --- .../native/NativeLibraryDslWithCocoapodsIT.kt | 92 +++++++++++++++---- .../lib/build.gradle | 12 +++ .../podspecs/myslib.podspec | 3 +- .../shared/build.gradle.kts | 14 +++ .../KotlinArtifactsPodspecExtension.kt | 12 ++- .../native/cocoapods/KotlinCocoapodsPlugin.kt | 10 +- .../tasks/GenerateArtifactPodspecTask.kt | 11 +++ 7 files changed, 127 insertions(+), 27 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeLibraryDslWithCocoapodsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeLibraryDslWithCocoapodsIT.kt index 9563819b0aa..3a5011952ce 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeLibraryDslWithCocoapodsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeLibraryDslWithCocoapodsIT.kt @@ -32,15 +32,15 @@ class NativeLibraryDslWithCocoapodsIT : BaseGradleIT() { build(":shared:tasks") { assertSuccessful() assertTasksRegistered( - ":shared:generateMylibPodspec", - ":shared:generateMyslibPodspec", - ":shared:generateMyframePodspec", - ":shared:generateMyfatframePodspec", - ":shared:generateSharedPodspec", - ":lib:generateGrooframePodspec", - ) - assertTasksNotRegistered( - ":shared:generateMyfatframewithoutpodspecPodspec", + ":shared:generateMylibStaticLibraryLinuxX64Podspec", + ":shared:generateMyslibSharedLibraryLinuxX64Podspec", + ":shared:generateMyframeFrameworkIosArm64Podspec", + ":shared:generateMyfatframeFatFrameworkPodspec", + ":shared:generateSharedXCFrameworkPodspec", + ":lib:generateGrooframeFrameworkIosArm64Podspec", + ":lib:generateGrooxcframeXCFrameworkPodspec", + ":shared:generateMyframewihtoutpodspecFrameworkIosArm64Podspec", + ":lib:generateGrooxcframewithoutpodspecXCFrameworkPodspec", ) } } @@ -51,7 +51,7 @@ class NativeLibraryDslWithCocoapodsIT : BaseGradleIT() { project { build(":shared:assembleMylibStaticLibraryLinuxX64") { assertSuccessful() - assertTasksExecuted(":shared:generateMylibPodspec") + assertTasksExecuted(":shared:generateMylibStaticLibraryLinuxX64Podspec") assertFilesContentEqual("podspecs/mylib.podspec", "/shared/build/out/static/mylib.podspec") } } @@ -62,29 +62,50 @@ class NativeLibraryDslWithCocoapodsIT : BaseGradleIT() { project { build(":shared:assembleMyslibSharedLibraryLinuxX64") { assertSuccessful() - assertTasksExecuted(":shared:generateMyslibPodspec") + assertTasksExecuted(":shared:generateMyslibSharedLibraryLinuxX64Podspec") assertFilesContentEqual("podspecs/myslib.podspec", "/shared/build/out/dynamic/myslib.podspec") } } } + @Test + fun `not generate podspec when withPodspec is empty`() { + project { + build(":shared:assembleMyslibwithoutpodspecSharedLibraryLinuxX64") { + assertSuccessful() + assertTasksSkipped(":shared:generateMyslibwithoutpodspecSharedLibraryLinuxX64Podspec") + assertContains("Skipping task ':shared:generateMyslibwithoutpodspecSharedLibraryLinuxX64Podspec' because there are no podspec attributes defined") + } + } + } + @Test fun `generate podspec when assembling framework`() { project { build(":shared:assembleMyframeFrameworkIosArm64") { assertSuccessful() - assertTasksExecuted(":shared:generateMyframePodspec") + assertTasksExecuted(":shared:generateMyframeFrameworkIosArm64Podspec") assertFilesContentEqual("podspecs/myframe.podspec", "/shared/build/out/framework/myframe.podspec") } } } + @Test + fun `not generate podspec when there is no withPodspec`() { + project { + build(":shared:assembleMyframewihtoutpodspecFrameworkIosArm64") { + assertSuccessful() + assertTasksSkipped(":shared:generateMyframewihtoutpodspecFrameworkIosArm64Podspec") + } + } + } + @Test fun `generate podspec when assembling fat framework`() { project { build(":shared:assembleMyfatframeFatFramework") { assertSuccessful() - assertTasksExecuted(":shared:generateMyfatframePodspec") + assertTasksExecuted(":shared:generateMyfatframeFatFrameworkPodspec") assertFilesContentEqual("podspecs/myfatframe.podspec", "/shared/build/out/fatframework/myfatframe.podspec") } } @@ -95,23 +116,62 @@ class NativeLibraryDslWithCocoapodsIT : BaseGradleIT() { project { build(":shared:assembleSharedXCFramework") { assertSuccessful() - assertTasksExecuted(":shared:generateSharedPodspec") + assertTasksExecuted(":shared:generateSharedXCFrameworkPodspec") assertFilesContentEqual("podspecs/shared.podspec", "/shared/build/out/xcframework/shared.podspec") } } } @Test - fun `generate podspec when assembling framework from groovy`() { + fun `generate podspec when assembling xcframework from groovy`() { project { build(":lib:assembleGrooframeFrameworkIosArm64") { assertSuccessful() - assertTasksExecuted(":lib:generateGrooframePodspec") + assertTasksExecuted(":lib:generateGrooframeFrameworkIosArm64Podspec") assertFilesContentEqual("podspecs/grooframe.podspec", "/lib/build/out/framework/grooframe.podspec") } } } + @Test + fun `not generate podspec from groovy when withPodspec is empty`() { + project { + build(":lib:assembleGrooxcframeXCFramework") { + assertSuccessful() + assertTasksSkipped(":lib:generateGrooxcframeXCFrameworkPodspec") + } + } + } + + @Test + fun `not generate podspec from groovy when there is no withPodspec`() { + project { + build(":lib:assembleGrooxcframewithoutpodspecXCFramework") { + assertSuccessful() + assertTasksSkipped(":lib:generateGrooxcframewithoutpodspecXCFrameworkPodspec") + } + } + } + + @Test + fun `generate podspecs when several frameworks have with the same name`() { + project { + projectDir.resolve("shared/build.gradle.kts").appendText(""" + kotlinArtifacts { + Native.Library { + target = linuxX64 + + withPodspec {} + } + } + """.trimIndent()) + + build(":shared:assembleSharedXCFramework") { + assertSuccessful() + } + } + } + private fun project(block: Project.() -> Unit) { transformProjectWithPluginsDsl("new-kn-library-dsl-cocoapods").block() } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/lib/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/lib/build.gradle index 54fdd39c2bb..16987bcb2f3 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/lib/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/lib/build.gradle @@ -23,9 +23,21 @@ kotlinArtifacts { attribute('homepage', 'https://example.com/lib') attribute('ios.deployment_target', '"10.0"') attribute('swift_versions', '[\'4\', \'5\']') + } + withPodspec { rawStatement(' # This is raw statement that is appended \'as is\' to the podspec') rawStatement(' spec.frameworks = \'CFNetwork\'') } } + + it.native.XCFramework("grooxcframe") { + targets(iosX64, iosArm64, iosSimulatorArm64) + + withPodspec {} + } + + it.native.XCFramework("grooxcframewithoutpodspec") { + targets(iosX64, iosArm64, iosSimulatorArm64) + } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/podspecs/myslib.podspec b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/podspecs/myslib.podspec index 8a8c58a22a9..c1460e8480b 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/podspecs/myslib.podspec +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/podspecs/myslib.podspec @@ -1,5 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'myslib' - spec.version = '0.1' spec.vendored_library = 'libmyslib.dylib' + + spec.version = '111' end diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/shared/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/shared/build.gradle.kts index 7f20220140c..68880c5f429 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/shared/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-kn-library-dsl-cocoapods/shared/build.gradle.kts @@ -42,6 +42,16 @@ kotlinArtifacts { modes(DEBUG) addModule(project(":lib")) + withPodspec { + attribute("version", "111") + } + } + Native.Library("myslibwithoutpodspec") { + target = linuxX64 + isStatic = false + modes(DEBUG) + addModule(project(":lib")) + withPodspec {} // intentionally empty } Native.Framework("myframe") { @@ -83,13 +93,17 @@ kotlinArtifacts { attribute("license", "MIT") attribute("homepage", "https://github.com/Alpaca/Alpaca") attribute("source", "{ :git => 'https://github.com/Alpaca/Alpaca.git', :tag => spec.version }") + } + withPodspec { attribute("ios.deployment_target", "10.0") attribute("osx.deployment_target", "10.12") attribute("watchos.deployment_target", "3.0") attribute("swift_versions", "['4', '5']") + } + withPodspec { rawStatement(" # This is raw statement that is appended 'as is' to the podspec") rawStatement(" spec.frameworks = 'CFNetwork'") } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinArtifactsPodspecExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinArtifactsPodspecExtension.kt index cf267e95c05..391693fe6e0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinArtifactsPodspecExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinArtifactsPodspecExtension.kt @@ -5,13 +5,11 @@ package org.jetbrains.kotlin.gradle.targets.native.cocoapods -import org.gradle.api.* import org.gradle.api.plugins.ExtensionAware import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin import org.jetbrains.kotlin.gradle.plugin.findExtension -import javax.inject.Inject -abstract class KotlinArtifactsPodspecExtension @Inject constructor(private val project: Project) { +abstract class KotlinArtifactsPodspecExtension { private val attrs = mutableMapOf() private val statements = mutableListOf() @@ -22,14 +20,20 @@ abstract class KotlinArtifactsPodspecExtension @Inject constructor(private val p internal val rawStatements: List get() = statements + /** + * Appends an attribute to the generated podspec + */ fun attribute(key: String, value: String) { attrs[key] = value } + /** + * Appends a statement 'as is' to the end of the generated podspec + */ fun rawStatement(statement: String) { statements.add(statement) } } -val ExtensionAware.kotlinArtifactsPodspecExtension: KotlinArtifactsPodspecExtension? +internal val ExtensionAware.kotlinArtifactsPodspecExtension: KotlinArtifactsPodspecExtension? get() = findExtension(KotlinCocoapodsPlugin.ARTIFACTS_PODSPEC_EXTENSION_NAME) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt index 548e2e8d321..10f6b8404a1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt @@ -412,7 +412,7 @@ open class KotlinCocoapodsPlugin : Plugin { ) { val artifactName = artifact.artifactName val assembleTask = project.tasks.named(artifact.taskName) - val podspecTaskName = lowerCamelCaseName("generate", artifactName, "podspec") + val podspecTaskName = lowerCamelCaseName("generate", artifact.name, "podspec") val artifactType = when (artifact) { is KotlinNativeLibrary -> when { @@ -446,16 +446,14 @@ open class KotlinCocoapodsPlugin : Plugin { cocoapodsExtension: CocoapodsExtension, ) { artifactsExtension.artifactConfigs.withType(KotlinNativeArtifactConfig::class.java) { artifactConfig -> - val podspecExtension = project.objects.newInstance(project) + val podspecExtension = project.objects.newInstance() artifactConfig.addExtension(ARTIFACTS_PODSPEC_EXTENSION_NAME, podspecExtension) } artifactsExtension.artifacts.withType(KotlinNativeArtifact::class.java) { artifact -> - val podspecExtension = artifact.kotlinArtifactsPodspecExtension + val podspecExtension = requireNotNull(artifact.kotlinArtifactsPodspecExtension) - if (podspecExtension != null) { - registerPodspecTask(project, artifact, podspecExtension, cocoapodsExtension) - } + registerPodspecTask(project, artifact, podspecExtension, cocoapodsExtension) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/GenerateArtifactPodspecTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/GenerateArtifactPodspecTask.kt index d3518057261..cd2aff2064c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/GenerateArtifactPodspecTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/GenerateArtifactPodspecTask.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.native.tasks import org.gradle.api.DefaultTask import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFile +import org.gradle.api.logging.Logger import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property @@ -23,6 +24,16 @@ abstract class GenerateArtifactPodspecTask : DefaultTask() { StaticLibrary, DynamicLibrary, Framework, FatFramework, XCFramework } + init { + this.onlyIf { + val shouldRun = attributes.get().isNotEmpty() || rawStatements.get().isNotEmpty() + if (!shouldRun) { + logger.info("Skipping task '$path' because there are no podspec attributes defined") + } + shouldRun + } + } + @get:Input abstract val specName: Property